ReGameDLL_CS/regamedll/dlls/bot/cs_bot_chatter.h
2016-01-25 23:17:37 +06:00

723 lines
22 KiB
C++

/*
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* In addition, as a special exception, the author gives permission to
* link the code of this program with the Half-Life Game Engine ("HL
* Engine") and Modified Game Libraries ("MODs") developed by Valve,
* L.L.C ("Valve"). You must obey the GNU General Public License in all
* respects for all of the code used other than the HL Engine and MODs
* from Valve. If you modify this file, you may extend this exception
* to your version of the file, but you are not obligated to do so. If
* you do not wish to do so, delete this exception statement from your
* version.
*
*/
#ifndef CS_BOT_CHATTER_H
#define CS_BOT_CHATTER_H
#ifdef _WIN32
#pragma once
#endif
#define UNDEFINED_COUNT 0xFFFF
#define MAX_PLACES_PER_MAP 64
#define UNDEFINED_SUBJECT (-1)
#define COUNT_MANY 4 // equal to or greater than this is "many"
class CCSBot;
class BotChatterInterface;
typedef unsigned int PlaceCriteria;
typedef unsigned int CountCriteria;
// A meme is a unit information that bots use to
// transmit information to each other via the radio
/* <2fe97b> ../cstrike/dlls/bot/cs_bot_chatter.h:42 */
class BotMeme
{
public:
void Transmit(CCSBot *sender) const; // transmit meme to other bots
virtual void Interpret(CCSBot *sender, CCSBot *receiver) const = 0; // cause the given bot to act on this meme
};/* size: 4, cachelines: 1, members: 1 */
class BotAllHostagesGoneMeme: public BotMeme
{
public:
virtual void Interpret(CCSBot *sender, CCSBot *receiver) const; // cause the given bot to act on this meme
#ifdef HOOK_GAMEDLL
void Interpret_(CCSBot *sender, CCSBot *receiver) const;
#endif //HOOK_GAMEDLL
};/* size: 4, cachelines: 1, members: 1 */
class BotHostageBeingTakenMeme: public BotMeme
{
public:
virtual void Interpret(CCSBot *sender, CCSBot *receiver) const; // cause the given bot to act on this meme
#ifdef HOOK_GAMEDLL
void Interpret_(CCSBot *sender, CCSBot *receiver) const;
#endif //HOOK_GAMEDLL
};/* size: 4, cachelines: 1, members: 1 */
/* <2ff7ef> ../cstrike/dlls/bot/cs_bot_chatter.h:53 */
class BotHelpMeme: public BotMeme
{
public:
BotHelpMeme(Place place = UNDEFINED_PLACE)
{
m_place = place;
}
virtual void Interpret(CCSBot *sender, CCSBot *receiver) const; // cause the given bot to act on this meme
#ifdef HOOK_GAMEDLL
void Interpret_(CCSBot *sender, CCSBot *receiver) const;
#endif //HOOK_GAMEDLL
private:
Place m_place;
};/* size: 8, cachelines: 1, members: 2 */
/* <2ff65e> ../cstrike/dlls/bot/cs_bot_chatter.h:70 */
class BotBombsiteStatusMeme: public BotMeme
{
public:
enum StatusType { CLEAR, PLANTED };
BotBombsiteStatusMeme(int zoneIndex, StatusType status)
{
m_zoneIndex = zoneIndex;
m_status = status;
}
virtual void Interpret(CCSBot *sender, CCSBot *receiver) const; // cause the given bot to act on this meme
#ifdef HOOK_GAMEDLL
void Interpret_(CCSBot *sender, CCSBot *receiver) const;
#endif //HOOK_GAMEDLL
private:
int m_zoneIndex; // the bombsite
StatusType m_status; // whether it is cleared or the bomb is there (planted)
};/* size: 12, cachelines: 1, members: 3 */
/* <2ff6de> ../cstrike/dlls/bot/cs_bot_chatter.h:87 */
class BotBombStatusMeme: public BotMeme
{
public:
BotBombStatusMeme(CSGameState::BombState state, const Vector &pos)
{
m_state = state;
m_pos = pos;
}
public:
virtual void Interpret(CCSBot *sender, CCSBot *receiver) const; // cause the given bot to act on this meme
#ifdef HOOK_GAMEDLL
void Interpret_(CCSBot *sender, CCSBot *receiver) const;
#endif //HOOK_GAMEDLL
private:
CSGameState::BombState m_state;
Vector m_pos;
};/* size: 20, cachelines: 1, members: 3 */
/* <2ff75d> ../cstrike/dlls/bot/cs_bot_chatter.h:101 */
class BotFollowMeme: public BotMeme
{
public:
virtual void Interpret(CCSBot *sender, CCSBot *receiver) const; // cause the given bot to act on this meme
#ifdef HOOK_GAMEDLL
void Interpret_(CCSBot *sender, CCSBot *receiver) const;
#endif //HOOK_GAMEDLL
};/* size: 4, cachelines: 1, members: 1 */
/* <2ff731> ../cstrike/dlls/bot/cs_bot_chatter.h:111 */
class BotDefendHereMeme: public BotMeme
{
public:
BotDefendHereMeme(const Vector &pos)
{
m_pos = pos;
}
virtual void Interpret(CCSBot *sender, CCSBot *receiver) const; // cause the given bot to act on this meme
#ifdef HOOK_GAMEDLL
void Interpret_(CCSBot *sender, CCSBot *receiver) const;
#endif //HOOK_GAMEDLL
private:
Vector m_pos;
};/* size: 16, cachelines: 1, members: 2 */
/* <2ff696> ../cstrike/dlls/bot/cs_bot_chatter.h:123 */
class BotWhereBombMeme: public BotMeme
{
public:
virtual void Interpret(CCSBot *sender, CCSBot *receiver) const; // cause the given bot to act on this meme
#ifdef HOOK_GAMEDLL
void Interpret_(CCSBot *sender, CCSBot *receiver) const;
#endif //HOOK_GAMEDLL
};/* size: 4, cachelines: 1, members: 1 */
/* <2ff81b> ../cstrike/dlls/bot/cs_bot_chatter.h:130 */
class BotRequestReportMeme: public BotMeme
{
public:
virtual void Interpret(CCSBot *sender, CCSBot *receiver) const; // cause the given bot to act on this meme
#ifdef HOOK_GAMEDLL
void Interpret_(CCSBot *sender, CCSBot *receiver) const;
#endif //HOOK_GAMEDLL
};/* size: 4, cachelines: 1, members: 1 */
enum BotStatementType
{
REPORT_VISIBLE_ENEMIES,
REPORT_ENEMY_ACTION,
REPORT_MY_CURRENT_TASK,
REPORT_MY_INTENTION,
REPORT_CRITICAL_EVENT,
REPORT_REQUEST_HELP,
REPORT_REQUEST_INFORMATION,
REPORT_ROUND_END,
REPORT_MY_PLAN,
REPORT_INFORMATION,
REPORT_EMOTE,
REPORT_ACKNOWLEDGE, // affirmative or negative
REPORT_ENEMIES_REMAINING,
REPORT_FRIENDLY_FIRE,
REPORT_KILLED_FRIEND,
//REPORT_ENEMY_LOST
NUM_BOT_STATEMENT_TYPES,
};
// BotSpeakables are the smallest unit of bot chatter.
// They represent a specific wav file of a phrase, and the criteria for which it is useful
class BotSpeakable
{
public:
BotSpeakable(void);
~BotSpeakable(void);
char *m_phrase;
float m_duration;
PlaceCriteria m_place;
CountCriteria m_count;
};/* size: 16, cachelines: 1, members: 4 */
typedef std::STD_VECTOR<BotSpeakable *> BotSpeakableVector;
typedef std::STD_VECTOR<BotSpeakableVector *> BotVoiceBankVector;
// The BotPhrase class is a collection of Speakables associated with a name, ID, and criteria
class BotPhrase
{
public:
char *GetSpeakable(int bankIndex, float *duration = NULL) const; // return a random speakable and its duration in seconds that meets the current criteria
// NOTE: Criteria must be set just before the GetSpeakable() call, since they are shared among all bots
void ClearCriteria(void) const;
void SetPlaceCriteria(PlaceCriteria place) const; // all returned phrases must have this place criteria
void SetCountCriteria(CountCriteria count) const; // all returned phrases must have this count criteria
const char *GetName(void) const { return m_name; }
Place GetID(void) const { return m_id; }
GameEventType GetRadioEquivalent(void) const { return m_radioEvent; }
bool IsImportant(void) const { return m_isImportant; } // return true if this phrase is part of an important statement
bool IsPlace(void) const { return m_isPlace; }
void Randomize(void); // randomly shuffle the speakable order
#ifndef HOOK_GAMEDLL
private:
#endif // HOOK_GAMEDLL
friend class BotPhraseManager;
BotPhrase(unsigned int id, bool isPlace);
~BotPhrase(void);
char *m_name;
Place m_id;
bool m_isPlace; // true if this is a Place phrase
GameEventType m_radioEvent;
bool m_isImportant; // mission-critical statement
mutable BotVoiceBankVector m_voiceBank; // array of voice banks (arrays of speakables)
std::STD_VECTOR<int> m_count; // number of speakables
mutable std::STD_VECTOR< int > m_index; // index of next speakable to return
int m_numVoiceBanks; // number of voice banks that have been initialized
void InitVoiceBank(int bankIndex); // sets up the vector of voice banks for the first bankIndex voice banks
mutable PlaceCriteria m_placeCriteria;
mutable CountCriteria m_countCriteria;
};/* size: 68, cachelines: 2, members: 11 */
typedef std::STD_LIST<BotPhrase *> BotPhraseList;
/* <2fea0e> ../cstrike/dlls/bot/cs_bot_chatter.h:239 */
inline void BotPhrase::ClearCriteria(void) const
{
m_placeCriteria = ANY_PLACE;
m_countCriteria = UNDEFINED_COUNT;
}
/* <2fea2a> ../cstrike/dlls/bot/cs_bot_chatter.h:245 */
inline void BotPhrase::SetPlaceCriteria(PlaceCriteria place) const
{
m_placeCriteria = place;
}
/* <2fea52> ../cstrike/dlls/bot/cs_bot_chatter.h:250 */
inline void BotPhrase::SetCountCriteria(CountCriteria count) const
{
m_countCriteria = count;
}
// The BotPhraseManager is a singleton that provides an interface to all BotPhrase collections
class BotPhraseManager
{
public:
BotPhraseManager(void);
~BotPhraseManager(void);
// initialize phrase system from database file for a specific voice bank (0 is the default voice bank)
bool Initialize(const char *filename, int bankIndex);
// invoked when round resets
void OnRoundRestart(void);
// invoked when map changes
void OnMapChange(void);
Place NameToID(const char *name) const;
const char *IDToName(Place id) const;
// given a name, return the associated phrase collection
const BotPhrase *GetPhrase(const char *name) const;
// given a name, return the associated Place phrase collection
const BotPhrase *GetPlace(const char *name) const;
// given an id, return the associated Place phrase collection
const BotPhrase *GetPlace(PlaceCriteria place) const;
const BotPhraseList *GetPlaceList(void) const { return &m_placeList; }
// return time last statement of given type was emitted by a teammate for the given place
float GetPlaceStatementInterval(Place place) const;
// set time of last statement of given type was emitted by a teammate for the given place
void ResetPlaceStatementInterval(Place place) const;
#ifndef HOOK_GAMEDLL
private:
#endif // HOOK_GAMEDLL
int FindPlaceIndex(Place where) const;
// master list of all phrase collections
BotPhraseList m_list;
// master list of all Place phrases
BotPhraseList m_placeList;
struct PlaceTimeInfo
{
Place placeID;
IntervalTimer timer;
};
mutable PlaceTimeInfo m_placeStatementHistory[ MAX_PLACES_PER_MAP ];
mutable int m_placeCount;
};/* size: 532, cachelines: 9, members: 4 */
/* <2fea95> ../cstrike/dlls/bot/cs_bot_chatter.h:298 */
inline int BotPhraseManager::FindPlaceIndex(Place where) const
{
for (int i = 0; i < m_placeCount; ++i)
{
if (m_placeStatementHistory[i].placeID == where)
return i;
}
if (m_placeCount < MAX_PLACES_PER_MAP)
{
m_placeStatementHistory[++m_placeCount].placeID = where;
m_placeStatementHistory[++m_placeCount].timer.Invalidate();
return m_placeCount - 1;
}
return -1;
}
/* <2ff83d> ../cstrike/dlls/bot/cs_bot_chatter.h:319 */
inline float BotPhraseManager::GetPlaceStatementInterval(Place place) const
{
int index = FindPlaceIndex(place);
if (index < 0)
return 999999.9f;
if (index >= m_placeCount)
return 999999.9f;
return m_placeStatementHistory[ index ].timer.GetElapsedTime();
}
/* <2ff876> ../cstrike/dlls/bot/cs_bot_chatter.h:335 */
inline void BotPhraseManager::ResetPlaceStatementInterval(Place place) const
{
int index = FindPlaceIndex(place);
if (index < 0)
return;
if (index >= m_placeCount)
return;
m_placeStatementHistory[index].timer.Reset();
}
// Statements are meaningful collections of phrases
class BotStatement
{
public:
BotStatement(BotChatterInterface *chatter, BotStatementType type, float expireDuration);
~BotStatement(void);
public:
BotChatterInterface *GetChatter(void) const { return m_chatter; }
CCSBot *GetOwner(void) const;
BotStatementType GetType(void) const { return m_type; } // return the type of statement this is
bool IsImportant(void) const; // return true if this statement is "important" and not personality chatter
bool HasSubject(void) const { return (m_subject != UNDEFINED_SUBJECT); }
void SetSubject(int playerID) { m_subject = playerID; } // who this statement is about
int GetSubject(void) const { return m_subject; } // who this statement is about
bool HasPlace(void) const { return (GetPlace()) ? true : false; }
Place GetPlace(void) const; // if this statement refers to a specific place, return that place
void SetPlace(Place where) { m_place = where; } // explicitly set place
bool HasCount(void) const; // return true if this statement has an associated count
bool IsRedundant(const BotStatement *say) const; // return true if this statement is the same as the given one
bool IsObsolete(void) const; // return true if this statement is no longer appropriate to say
void Convert(const BotStatement *say); // possibly change what were going to say base on what teammate is saying
void AppendPhrase(const BotPhrase *phrase);
void SetStartTime(float timestamp) { m_startTime = timestamp; } // define the earliest time this statement can be spoken
float GetStartTime(void) const { return m_startTime; }
enum ConditionType
{
IS_IN_COMBAT,
RADIO_SILENCE,
ENEMIES_REMAINING,
NUM_CONDITIONS,
};
void AddCondition(ConditionType condition); // conditions must be true for the statement to be spoken
bool IsValid(void) const; // verify all attached conditions
enum ContextType
{
CURRENT_ENEMY_COUNT,
REMAINING_ENEMY_COUNT,
SHORT_DELAY,
LONG_DELAY,
ACCUMULATE_ENEMIES_DELAY,
};
void AppendPhrase(ContextType contextPhrase); // special phrases that depend on the context
bool Update(void); // emit statement over time, return false if statement is done
bool IsSpeaking(void) const { return m_isSpeaking; } // return true if this statement is currently being spoken
float GetTimestamp(void) const { return m_timestamp; } // get time statement was created (but not necessarily started talking)
void AttachMeme(BotMeme *meme); // attach a meme to this statement, to be transmitted to other friendly bots when spoken
public:
friend class BotChatterInterface;
BotChatterInterface *m_chatter; // the chatter system this statement is part of
BotStatement *m_next, *m_prev; // linked list hooks
BotStatementType m_type; // what kind of statement this is
int m_subject; // who this subject is about
Place m_place; // explicit place - note some phrases have implicit places as well
BotMeme *m_meme; // a statement can only have a single meme for now
float m_timestamp; // time when message was created
float m_startTime; // the earliest time this statement can be spoken
float m_expireTime; // time when this statement is no longer valid
float m_speakTimestamp; // time when message began being spoken
bool m_isSpeaking; // true if this statement is current being spoken
float m_nextTime; // time for next phrase to begin
enum { MAX_BOT_PHRASES = 4 };
struct
{
bool isPhrase;
union
{
const BotPhrase *phrase;
ContextType context;
};
}
m_statement[ MAX_BOT_PHRASES ];
enum { MAX_BOT_CONDITIONS = 4 };
ConditionType m_condition[ MAX_BOT_CONDITIONS ]; // conditions that must be true for the statement to be said
int m_conditionCount;
int m_index; // m_index refers to the phrase currently being spoken, or -1 if we havent started yet
int m_count;
};/* size: 112, cachelines: 2, members: 18 */
// This class defines the interface to the bot radio chatter system
class BotChatterInterface
{
public:
BotChatterInterface(void) {};
BotChatterInterface(CCSBot *me);
~BotChatterInterface();
void Reset(void); // reset to initial state
void Update(void); // process ongoing chatter
void OnEvent(GameEventType event, CBaseEntity *entity, CBaseEntity *other); // invoked when event occurs in the game (some events have NULL entities)
void OnDeath(void); // invoked when we die
enum VerbosityType
{
NORMAL, // full chatter
MINIMAL, // only scenario-critical events
RADIO, // use the standard radio instead
OFF // no chatter at all
};
VerbosityType GetVerbosity(void) const; // return our current level of verbosity
CCSBot *GetOwner(void) const { return m_me; }
bool IsTalking(void) const; // return true if we are currently talking
float GetRadioSilenceDuration(void); // return time since any teammate said anything
void ResetRadioSilenceDuration(void);
enum { MUST_ADD = 1 };
void AddStatement(BotStatement *statement, bool mustAdd = false); // register a statement for speaking
void RemoveStatement(BotStatement *statement); // remove a statement
BotStatement *GetActiveStatement(void); // returns the statement that is being spoken, or is next to be spoken if no-one is speaking now
BotStatement *GetStatement(void) const; // returns our current statement, or NULL if we aren't speaking
int GetPitch(void) const { return m_pitch; }
// things the bots can say
void Say(const char *phraseName, float lifetime = 3.0f, float delay = 0.0f);
void AnnouncePlan(const char *phraseName, Place place);
void Affirmative(void);
void Negative(void);
void EnemySpotted(void); // report enemy sightings
void KilledMyEnemy(int victimID);
void EnemiesRemaining(void);
NOXREF void Clear(Place place);
void ReportIn(void); // ask for current situation
void ReportingIn(void); // report current situation
bool NeedBackup(void);
void PinnedDown(void);
void Scared(void);
void HeardNoise(const Vector *pos);
void TheyPickedUpTheBomb(void);
void GoingToPlantTheBomb(Place place);
void BombsiteClear(int zoneIndex);
void FoundPlantedBomb(int zoneIndex);
void PlantingTheBomb(Place place);
void SpottedBomber(CBasePlayer *bomber);
void SpottedLooseBomb(CBaseEntity *bomb);
NOXREF void GuardingLooseBomb(CBaseEntity *bomb);
void RequestBombLocation(void);
#define IS_PLAN true
void GuardingHostages(Place place, bool isPlan = false);
void GuardingHostageEscapeZone(bool isPlan = false);
void HostagesBeingTaken(void);
void HostagesTaken(void);
void TalkingToHostages(void);
void EscortingHostages(void);
NOXREF void HostageDown(void);
void CelebrateWin(void);
void Encourage(const char *phraseName, float repeatInterval = 10.0f, float lifetime = 3.0f); // "encourage" the player to do the scenario
void KilledFriend(void);
void FriendlyFire(void);
bool SeesAtLeastOneEnemy(void) const { return m_seeAtLeastOneEnemy; }
#ifndef HOOK_GAMEDLL
private:
#endif // HOOK_GAMEDLL
BotStatement *m_statementList; // list of all active/pending messages for this bot
void ReportEnemies(void); // track nearby enemy count and generate enemy activity statements
bool ShouldSpeak(void) const; // return true if we speaking makes sense now
CCSBot *m_me; // the bot this chatter is for
bool m_seeAtLeastOneEnemy;
float m_timeWhenSawFirstEnemy;
bool m_reportedEnemies;
bool m_requestedBombLocation; // true if we already asked where the bomb has been planted
int m_pitch;
static IntervalTimer IMPL(m_radioSilenceInterval)[2]; // one timer for each team
IntervalTimer m_needBackupInterval;
IntervalTimer m_spottedBomberInterval;
IntervalTimer m_scaredInterval;
IntervalTimer m_planInterval;
CountdownTimer m_spottedLooseBombTimer;
CountdownTimer m_heardNoiseTimer;
CountdownTimer m_escortingHostageTimer;
static CountdownTimer IMPL(m_encourageTimer); // timer to know when we can "encourage" the human player again - shared by all bots
};/* size: 64, cachelines: 1, members: 16 */
/* <2fec2d> ../cstrike/dlls/bot/cs_bot_chatter.h:572 */
inline BotChatterInterface::VerbosityType BotChatterInterface::GetVerbosity(void) const
{
const char *string = cv_bot_chatter.string;
if (string == NULL)
return NORMAL;
if (string[0] == 'm' || string[0] == 'M')
return MINIMAL;
if (string[0] == 'r' || string[0] == 'R')
return RADIO;
if (string[0] == 'o' || string[0] == 'O')
return OFF;
return NORMAL;
}
/* <2fec4a> ../cstrike/dlls/bot/cs_bot_chatter.h:590 */
inline bool BotChatterInterface::IsTalking(void) const
{
if (m_statementList != NULL)
{
return m_statementList->IsSpeaking();
}
return false;
}
/* <3f2bad> ../cstrike/dlls/bot/cs_bot_chatter.h:596 */
inline BotStatement *BotChatterInterface::GetStatement(void) const
{
return m_statementList;
}
#ifdef HOOK_GAMEDLL
#define TheBotPhrases (*pTheBotPhrases)
#define g_pSelectedZombieSpawn (*pg_pSelectedZombieSpawn)
#endif // HOOK_GAMEDLL
extern BotPhraseManager *TheBotPhrases;
extern CBaseEntity *g_pSelectedZombieSpawn;
/* <5c4dcf> ../cstrike/dlls/bot/cs_bot_chatter.h:604 */
inline void BotChatterInterface::Say(const char *phraseName, float lifetime, float delay)
{
BotStatement *say = new BotStatement(this, REPORT_MY_INTENTION, lifetime);
say->AppendPhrase(TheBotPhrases->GetPhrase(phraseName));
if (delay > 0.0f)
say->SetStartTime(gpGlobals->time + delay);
AddStatement(say);
}
const Vector *GetRandomSpotAtPlace(Place place);
#ifdef HOOK_GAMEDLL
typedef void (BotStatement::*APPEND_PHRASE_CONTEXT)(BotStatement::ContextType);
typedef void (BotStatement::*APPEND_PHRASE_BOTPHRASE)(const BotPhrase *);
typedef const BotPhrase *(BotPhraseManager::*GET_PLACE_NAME)(const char *name) const;
typedef const BotPhrase *(BotPhraseManager::*GET_PLACE_PLACE)(PlaceCriteria place) const;
// refs
extern void (*pBotPhrase__Randomize)(void);
#endif // HOOK_GAMEDLL
#endif // CS_BOT_CHATTER_H