aim: verify camp angles from nav data before using them
aim: tweaked a bit grenade handling, so bots should use them more aim: reduce time between selecting grenade and throwing it away aim: removed hacks in look angles code, due to removing yb_whoose_your_daddy cvar aim: use direct enemy origin from visibility check, and not re-calculate it aim: update enemy prediction, so it now depends on frame interval for a bot aim: additional height offset are tweaked, and now used only for difficulty 4 nav: tweaked a bit player avoidance code, and it's not preventing bot from checking terrain nav: do not check banned nodes, when bucket sizes re too low nav: cover nodes are now selected depending on total bots on server nav: let bot enter pause task after long jump nav: extend velocity by a little for a jump, like it was in first versions of bot nav: stuck checking is now taken in account lower minimal speed if bot is ducking fix: navigation reachability timers, so bots will have correct current node index while camping fix: bots are unable to finish pickup or destroy breakable task, if target is not reachable fix: cover nodes are now calculated as they should fix: manual calling bots add_[t/ct] now ignores yb_join_team cvar bot: tweaked a little difficulty levels, so level 4 is now nightmare level, and 3 is very heard bot: minor refactoring and moving functions to correct source file bot: add yb_economics_disrespect_percent, so bots can ignore economics and buy more different guns bot: add yb_check_darkness that allows to disable darkness checks for bot, thus disallowing usage of flashlight bot: camp buttons are now lightly depends on bot health chat: welcome chat message from bots is now sent during first freeze time period crlib: switch over to stdint.h and remove crlib-own types crlib: fixed alignment in sse code
This commit is contained in:
parent
722e4eda93
commit
29c00565dc
31 changed files with 1395 additions and 1305 deletions
|
|
@ -1 +1 @@
|
|||
Subproject commit dade2ade585d7fbd3ac91dec93cd70c92225e832
|
||||
Subproject commit 58136b52a1391af4c603f846cd8e46f7cdb4dd1f
|
||||
|
|
@ -26,8 +26,8 @@ typedef struct hudtextparms_s {
|
|||
float x;
|
||||
float y;
|
||||
int effect;
|
||||
uint8 r1, g1, b1, a1;
|
||||
uint8 r2, g2, b2, a2;
|
||||
uint8_t r1, g1, b1, a1;
|
||||
uint8_t r2, g2, b2, a2;
|
||||
float fadeinTime;
|
||||
float fadeoutTime;
|
||||
float holdTime;
|
||||
|
|
@ -68,7 +68,7 @@ typedef struct usercmd_s {
|
|||
vec3_t impact_position;
|
||||
} usercmd_t;
|
||||
|
||||
typedef uint32 CRC32_t;
|
||||
typedef uint32_t CRC32_t;
|
||||
|
||||
// Engine hands this to DLLs for functionality callbacks
|
||||
|
||||
|
|
@ -136,7 +136,7 @@ typedef struct enginefuncs_s {
|
|||
void (*pfnCVarSetString) (const char *szVarName, const char *szValue);
|
||||
void (*pfnAlertMessage) (ALERT_TYPE atype, const char *szFmt, ...);
|
||||
void (*pfnEngineFprintf) (void *pfile, char *szFmt, ...);
|
||||
void *(*pfnPvAllocEntPrivateData) (edict_t *ent, int32 cb);
|
||||
void *(*pfnPvAllocEntPrivateData) (edict_t *ent, int32_t cb);
|
||||
void *(*pfnPvEntPrivateData) (edict_t *ent);
|
||||
void (*pfnFreeEntPrivateData) (edict_t *ent);
|
||||
const char *(*pfnSzFromIndex) (int stingPtr);
|
||||
|
|
@ -151,8 +151,8 @@ typedef struct enginefuncs_s {
|
|||
int (*pfnRegUserMsg) (const char *pszName, int iSize);
|
||||
void (*pfnAnimationAutomove) (const edict_t *ent, float flTime);
|
||||
void (*pfnGetBonePosition) (const edict_t *ent, int iBone, float *rgflOrigin, float *rgflAngles);
|
||||
uint32 (*pfnFunctionFromName) (const char *pName);
|
||||
const char *(*pfnNameForFunction) (uint32 function);
|
||||
uint32_t (*pfnFunctionFromName) (const char *pName);
|
||||
const char *(*pfnNameForFunction) (uint32_t function);
|
||||
void (*pfnClientPrintf) (edict_t *ent, PRINT_TYPE ptype, const char *szMsg); // JOHN: engine callbacks so game DLL can print messages to individual clients
|
||||
void (*pfnServerPrint) (const char *szMsg);
|
||||
const char *(*pfnCmd_Args) (); // these 3 added
|
||||
|
|
@ -161,14 +161,14 @@ typedef struct enginefuncs_s {
|
|||
void (*pfnGetAttachment) (const edict_t *ent, int iAttachment, float *rgflOrigin, float *rgflAngles);
|
||||
void (*pfnCRC32_Init) (CRC32_t *pulCRC);
|
||||
void (*pfnCRC32_ProcessBuffer) (CRC32_t *pulCRC, void *p, int len);
|
||||
void (*pfnCRC32_ProcessByte) (CRC32_t *pulCRC, uint8 ch);
|
||||
void (*pfnCRC32_ProcessByte) (CRC32_t *pulCRC, uint8_t ch);
|
||||
CRC32_t (*pfnCRC32_Final) (CRC32_t pulCRC);
|
||||
int32 (*pfnRandomLong) (int32 lLow, int32 lHigh);
|
||||
int32_t (*pfnRandomLong) (int32_t lLow, int32_t lHigh);
|
||||
float (*pfnRandomFloat) (float flLow, float flHigh);
|
||||
void (*pfnSetView) (const edict_t *client, const edict_t *pViewent);
|
||||
float (*pfnTime) ();
|
||||
void (*pfnCrosshairAngle) (const edict_t *client, float pitch, float yaw);
|
||||
uint8 *(*pfnLoadFileForMe) (char const *szFilename, int *pLength);
|
||||
uint8_t *(*pfnLoadFileForMe) (char const *szFilename, int *pLength);
|
||||
void (*pfnFreeFile) (void *buffer);
|
||||
void (*pfnEndSection) (const char *pszSectionName); // trigger_endsection
|
||||
int (*pfnCompareFileTime) (char *filename1, char *filename2, int *compare);
|
||||
|
|
@ -177,7 +177,7 @@ typedef struct enginefuncs_s {
|
|||
void (*pfnFadeClientVolume) (const edict_t *ent, int fadePercent, int fadeOutSeconds, int holdTime, int fadeInSeconds);
|
||||
void (*pfnSetClientMaxspeed) (const edict_t *ent, float fNewMaxspeed);
|
||||
edict_t *(*pfnCreateFakeClient) (const char *netname); // returns nullptr if fake client can't be created
|
||||
void (*pfnRunPlayerMove) (edict_t *fakeclient, const float *viewangles, float forwardmove, float sidemove, float upmove, uint16 buttons, uint8 impulse, uint8 msec);
|
||||
void (*pfnRunPlayerMove) (edict_t *fakeclient, const float *viewangles, float forwardmove, float sidemove, float upmove, uint16_t buttons, uint8_t impulse, uint8_t msec);
|
||||
int (*pfnNumberOfEntities) ();
|
||||
char *(*pfnGetInfoKeyBuffer) (edict_t *e); // passing in nullptr gets the serverinfo
|
||||
char *(*pfnInfoKeyValue) (char *infobuffer, char const *key);
|
||||
|
|
@ -196,14 +196,14 @@ typedef struct enginefuncs_s {
|
|||
const char *(*pfnGetPhysicsKeyValue) (const edict_t *client, const char *key);
|
||||
void (*pfnSetPhysicsKeyValue) (const edict_t *client, const char *key, const char *value);
|
||||
const char *(*pfnGetPhysicsInfoString) (const edict_t *client);
|
||||
uint16 (*pfnPrecacheEvent) (int type, const char *psz);
|
||||
void (*pfnPlaybackEvent) (int flags, const edict_t *pInvoker, uint16 evIndexOfEntity, float delay, float *origin, float *angles, float fparam1, float fparam2, int iparam1, int iparam2, int bparam1, int bparam2);
|
||||
uint8 *(*pfnSetFatPVS) (float *org);
|
||||
uint8 *(*pfnSetFatPAS) (float *org);
|
||||
int (*pfnCheckVisibility) (const edict_t *entity, uint8 *pset);
|
||||
uint16_t (*pfnPrecacheEvent) (int type, const char *psz);
|
||||
void (*pfnPlaybackEvent) (int flags, const edict_t *pInvoker, uint16_t evIndexOfEntity, float delay, float *origin, float *angles, float fparam1, float fparam2, int iparam1, int iparam2, int bparam1, int bparam2);
|
||||
uint8_t *(*pfnSetFatPVS) (float *org);
|
||||
uint8_t *(*pfnSetFatPAS) (float *org);
|
||||
int (*pfnCheckVisibility) (const edict_t *entity, uint8_t *pset);
|
||||
void (*pfnDeltaSetField) (struct delta_s *pFields, const char *fieldname);
|
||||
void (*pfnDeltaUnsetField) (struct delta_s *pFields, const char *fieldname);
|
||||
void (*pfnDeltaAddEncoder) (char *name, void (*conditionalencode) (struct delta_s *pFields, const uint8 *from, const uint8 *to));
|
||||
void (*pfnDeltaAddEncoder) (char *name, void (*conditionalencode) (struct delta_s *pFields, const uint8_t *from, const uint8_t *to));
|
||||
int (*pfnGetCurrentPlayer) ();
|
||||
int (*pfnCanSkipPlayer) (const edict_t *player);
|
||||
int (*pfnDeltaFindField) (struct delta_s *pFields, const char *fieldname);
|
||||
|
|
@ -246,7 +246,7 @@ typedef struct KeyValueData_s {
|
|||
char *szClassName; // in: entity classname
|
||||
char const *szKeyName; // in: name of key
|
||||
char *szValue; // in: value of key
|
||||
int32 fHandled; // out: DLL sets to true if key-value pair was understood
|
||||
int32_t fHandled; // out: DLL sets to true if key-value pair was understood
|
||||
} KeyValueData;
|
||||
|
||||
typedef struct customization_s customization_t;
|
||||
|
|
@ -306,9 +306,9 @@ typedef struct {
|
|||
void (*pfnPM_Move) (struct playermove_s *ppmove, int server);
|
||||
void (*pfnPM_Init) (struct playermove_s *ppmove);
|
||||
char (*pfnPM_FindTextureType) (char *name);
|
||||
void (*pfnSetupVisibility) (struct edict_s *pViewEntity, struct edict_s *client, uint8 **pvs, uint8 **pas);
|
||||
void (*pfnSetupVisibility) (struct edict_s *pViewEntity, struct edict_s *client, uint8_t **pvs, uint8_t **pas);
|
||||
void (*pfnUpdateClientData) (const struct edict_s *ent, int sendweapons, struct clientdata_s *cd);
|
||||
int (*pfnAddToFullPack) (struct entity_state_s *state, int e, edict_t *ent, edict_t *host, int hostflags, int player, uint8 *pSet);
|
||||
int (*pfnAddToFullPack) (struct entity_state_s *state, int e, edict_t *ent, edict_t *host, int hostflags, int player, uint8_t *pSet);
|
||||
void (*pfnCreateBaseline) (int player, int eindex, struct entity_state_s *baseline, struct edict_s *entity, int playermodelindex, float *player_mins, float *player_maxs);
|
||||
void (*pfnRegisterEncoders) ();
|
||||
int (*pfnGetWeaponData) (struct edict_s *player, struct weapon_data_s *info);
|
||||
|
|
|
|||
|
|
@ -56,8 +56,6 @@ public:
|
|||
};
|
||||
|
||||
typedef cr::Vector vec3_t;
|
||||
using namespace cr::types;
|
||||
|
||||
typedef struct edict_s edict_t;
|
||||
|
||||
#include "const.h"
|
||||
|
|
@ -105,7 +103,7 @@ static inline int MAKE_STRING (const char *val) {
|
|||
return static_cast <int> (ptrdiff);
|
||||
}
|
||||
#else
|
||||
#define MAKE_STRING(str) ((uint64)(str) - (uint64)(STRING(0)))
|
||||
#define MAKE_STRING(str) ((uint64_t)(str) - (uint64_t)(STRING(0)))
|
||||
#endif
|
||||
|
||||
inline const char *string_t::chars (size_t shift) const {
|
||||
|
|
@ -114,7 +112,7 @@ inline const char *string_t::chars (size_t shift) const {
|
|||
return cr::strings.isEmpty (result) ? &cr::kNullChar : (result + shift);
|
||||
}
|
||||
|
||||
enum HLBool : int32 {
|
||||
enum HLBool : int32_t {
|
||||
HLFalse, HLTrue
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -109,8 +109,8 @@ typedef struct entvars_s {
|
|||
float frame; // % playback position in animation sequences (0..255)
|
||||
float animtime; // world time when frame was set
|
||||
float framerate; // animation playback rate (-8x to 8x)
|
||||
uint8 controller[4]; // bone controller setting (0..255)
|
||||
uint8 blending[2]; // blending amount between sub-sequences (0..255)
|
||||
uint8_t controller[4]; // bone controller setting (0..255)
|
||||
uint8_t blending[2]; // blending amount between sub-sequences (0..255)
|
||||
|
||||
float scale; // sprite rendering scale (0..255)
|
||||
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ static inline int MAKE_STRING (const char *val) {
|
|||
return static_cast <int> (ptrdiff);
|
||||
}
|
||||
#else
|
||||
#define MAKE_STRING(str) ((uint64)(str) - (uint64)(STRING(0)))
|
||||
#define MAKE_STRING(str) ((uint64_t)(str) - (uint64_t)(STRING(0)))
|
||||
#endif
|
||||
|
||||
#define ENGINE_STR(str) (const_cast <char *> (STRING (engfuncs.pfnAllocString (str))))
|
||||
|
|
@ -53,8 +53,8 @@ typedef struct hudtextparms_s {
|
|||
float x;
|
||||
float y;
|
||||
int effect;
|
||||
uint8 r1, g1, b1, a1;
|
||||
uint8 r2, g2, b2, a2;
|
||||
uint8_t r1, g1, b1, a1;
|
||||
uint8_t r2, g2, b2, a2;
|
||||
float fadeinTime;
|
||||
float fadeoutTime;
|
||||
float holdTime;
|
||||
|
|
|
|||
34
inc/config.h
34
inc/config.h
|
|
@ -32,9 +32,9 @@ class BotConfig final : public Singleton <BotConfig> {
|
|||
public:
|
||||
struct DifficultyData {
|
||||
float reaction[2] {};
|
||||
int32 headshotPct {};
|
||||
int32 seenThruPct {};
|
||||
int32 hearThruPct {};
|
||||
int32_t headshotPct {};
|
||||
int32_t seenThruPct {};
|
||||
int32_t hearThruPct {};
|
||||
};
|
||||
|
||||
private:
|
||||
|
|
@ -49,16 +49,16 @@ private:
|
|||
StringArray m_logos {};
|
||||
StringArray m_avatars {};
|
||||
|
||||
HashMap <uint32, String, Hash <int32>> m_language {};
|
||||
HashMap <int32, DifficultyData> m_difficulty {};
|
||||
HashMap <uint32_t, String, Hash <int32_t>> m_language {};
|
||||
HashMap <int32_t, DifficultyData> m_difficulty {};
|
||||
HashMap <String, String> m_custom {};
|
||||
|
||||
// default tables for personality weapon preferences, overridden by weapon.cfg
|
||||
SmallArray <int32> m_normalWeaponPrefs = { 0, 2, 1, 4, 5, 6, 3, 12, 10, 24, 25, 13, 11, 8, 7, 22, 23, 18, 21, 17, 19, 15, 17, 9, 14, 16 };
|
||||
SmallArray <int32> m_rusherWeaponPrefs = { 0, 2, 1, 4, 5, 6, 3, 24, 19, 22, 23, 20, 21, 10, 12, 13, 7, 8, 11, 9, 18, 17, 19, 25, 15, 16 };
|
||||
SmallArray <int32> m_carefulWeaponPrefs = { 0, 2, 1, 4, 25, 6, 3, 7, 8, 12, 10, 13, 11, 9, 24, 18, 14, 17, 16, 15, 19, 20, 21, 22, 23, 5 };
|
||||
SmallArray <int32> m_botBuyEconomyTable = { 1900, 2100, 2100, 4000, 6000, 7000, 16000, 1200, 800, 1000, 3000 };
|
||||
SmallArray <int32> m_grenadeBuyPrecent = { 95, 85, 60 };
|
||||
SmallArray <int32_t> m_normalWeaponPrefs = { 0, 2, 1, 4, 5, 6, 3, 12, 10, 24, 25, 13, 11, 8, 7, 22, 23, 18, 21, 17, 19, 15, 17, 9, 14, 16 };
|
||||
SmallArray <int32_t> m_rusherWeaponPrefs = { 0, 2, 1, 4, 5, 6, 3, 24, 19, 22, 23, 20, 21, 10, 12, 13, 7, 8, 11, 9, 18, 17, 19, 25, 15, 16 };
|
||||
SmallArray <int32_t> m_carefulWeaponPrefs = { 0, 2, 1, 4, 25, 6, 3, 7, 8, 12, 10, 13, 11, 9, 24, 18, 14, 17, 16, 15, 19, 20, 21, 22, 23, 5 };
|
||||
SmallArray <int32_t> m_botBuyEconomyTable = { 1900, 2100, 2100, 4000, 6000, 7000, 16000, 1200, 800, 1000, 3000 };
|
||||
SmallArray <int32_t> m_grenadeBuyPrecent = { 95, 85, 60 };
|
||||
|
||||
public:
|
||||
BotConfig ();
|
||||
|
|
@ -138,7 +138,7 @@ private:
|
|||
};
|
||||
|
||||
// hash the lang string, only the letters
|
||||
uint32 hashLangString (StringRef str);
|
||||
uint32_t hashLangString (StringRef str);
|
||||
|
||||
public:
|
||||
|
||||
|
|
@ -188,7 +188,7 @@ public:
|
|||
}
|
||||
|
||||
// get's weapons type by id
|
||||
int32 getWeaponType (int id) const {
|
||||
int32_t getWeaponType (int id) const {
|
||||
for (const auto &weapon : m_weapons) {
|
||||
if (weapon.id == id) {
|
||||
return weapon.type;
|
||||
|
|
@ -198,7 +198,7 @@ public:
|
|||
}
|
||||
|
||||
// get's weapon preferences for personality
|
||||
int32 *getWeaponPrefs (int personality) const {
|
||||
int32_t *getWeaponPrefs (int personality) const {
|
||||
switch (personality) {
|
||||
case Personality::Normal:
|
||||
default:
|
||||
|
|
@ -213,7 +213,7 @@ public:
|
|||
}
|
||||
|
||||
// get's the difficulty level tweaks
|
||||
DifficultyData *getDifficultyTweaks (int32 level) {
|
||||
DifficultyData *getDifficultyTweaks (int32_t level) {
|
||||
if (level < Difficulty::Noob || level > Difficulty::Expert) {
|
||||
return &m_difficulty[Difficulty::Expert];
|
||||
}
|
||||
|
|
@ -221,7 +221,7 @@ public:
|
|||
}
|
||||
|
||||
// get economics value
|
||||
int32 *getEconLimit () {
|
||||
int32_t *getEconLimit () {
|
||||
return m_botBuyEconomyTable.data ();
|
||||
}
|
||||
|
||||
|
|
@ -239,8 +239,8 @@ public:
|
|||
}
|
||||
|
||||
// get's random logo index
|
||||
int32 getRandomLogoIndex () const {
|
||||
return static_cast <int32> (m_logos.index (m_logos.random ()));
|
||||
int32_t getRandomLogoIndex () const {
|
||||
return static_cast <int32_t> (m_logos.index (m_logos.random ()));
|
||||
}
|
||||
|
||||
// get random name by index
|
||||
|
|
|
|||
|
|
@ -52,13 +52,13 @@ public:
|
|||
|
||||
// queued text message to prevent overflow with rapid output
|
||||
struct PrintQueue {
|
||||
int32 destination {};
|
||||
int32_t destination {};
|
||||
String text;
|
||||
|
||||
public:
|
||||
explicit PrintQueue () = default;
|
||||
|
||||
PrintQueue (int32 destination, StringRef text) : destination (destination), text (text)
|
||||
PrintQueue (int32_t destination, StringRef text) : destination (destination), text (text)
|
||||
{ }
|
||||
};
|
||||
|
||||
|
|
|
|||
36
inc/engine.h
36
inc/engine.h
|
|
@ -75,14 +75,14 @@ struct ConVarReg {
|
|||
float initial, min, max;
|
||||
bool missing;
|
||||
bool bounded;
|
||||
int32 type;
|
||||
int32_t type;
|
||||
};
|
||||
|
||||
// entity prototype
|
||||
using EntityFunction = void (*) (entvars_t *);
|
||||
|
||||
// rehlds has this fixed, but original hlds doesn't allocate string space passed to precache* argument, so game will crash when unloading module using metamod
|
||||
class EngineWrap final : public DenyCopying {
|
||||
class EngineWrap final {
|
||||
public:
|
||||
EngineWrap () = default;
|
||||
~EngineWrap () = default;
|
||||
|
|
@ -93,11 +93,11 @@ private:
|
|||
}
|
||||
|
||||
public:
|
||||
int32 precacheModel (const char *model) const {
|
||||
int32_t precacheModel (const char *model) const {
|
||||
return engfuncs.pfnPrecacheModel (allocStr (model));
|
||||
}
|
||||
|
||||
int32 precacheSound (const char *sound) const {
|
||||
int32_t precacheSound (const char *sound) const {
|
||||
return engfuncs.pfnPrecacheSound (allocStr (sound));
|
||||
}
|
||||
|
||||
|
|
@ -182,7 +182,7 @@ public:
|
|||
void prepareBotArgs (edict_t *ent, String str);
|
||||
|
||||
// adds cvar to registration stack
|
||||
void addNewCvar (const char *name, const char *value, const char *info, bool bounded, float min, float max, int32 varType, bool missingAction, const char *regval, class ConVar *self);
|
||||
void addNewCvar (const char *name, const char *value, const char *info, bool bounded, float min, float max, int32_t varType, bool missingAction, const char *regval, class ConVar *self);
|
||||
|
||||
// check the cvar bounds
|
||||
void checkCvarsBounds ();
|
||||
|
|
@ -240,7 +240,7 @@ public:
|
|||
}
|
||||
|
||||
// gets custom engine argv for client command
|
||||
const char *botArgv (int32 index) const {
|
||||
const char *botArgv (int32_t index) const {
|
||||
if (static_cast <size_t> (index) >= m_botArgs.length ()) {
|
||||
return "";
|
||||
}
|
||||
|
|
@ -248,8 +248,8 @@ public:
|
|||
}
|
||||
|
||||
// gets custom engine argc for client command
|
||||
int32 botArgc () const {
|
||||
return m_botArgs.length <int32> ();
|
||||
int32_t botArgc () const {
|
||||
return m_botArgs.length <int32_t> ();
|
||||
}
|
||||
|
||||
// gets edict pointer out of entity index
|
||||
|
|
@ -314,10 +314,10 @@ public:
|
|||
void setPlayerStartDrawModels ();
|
||||
|
||||
// check the engine visibility wrapper
|
||||
bool checkVisibility (edict_t *ent, uint8 *set);
|
||||
bool checkVisibility (edict_t *ent, uint8_t *set);
|
||||
|
||||
// get pvs/pas visibility set
|
||||
uint8 *getVisibilitySet (Bot *bot, bool pvs);
|
||||
uint8_t *getVisibilitySet (Bot *bot, bool pvs);
|
||||
|
||||
// what kind of game engine / game dll / mod / tool we're running ?
|
||||
bool is (const int type) const {
|
||||
|
|
@ -409,11 +409,11 @@ public:
|
|||
~ConVar () = default;
|
||||
|
||||
public:
|
||||
ConVar (const char *name, const char *initval, int32 type = Var::NoServer, bool regMissing = false, const char *regVal = nullptr) : ptr (nullptr) {
|
||||
ConVar (const char *name, const char *initval, int32_t type = Var::NoServer, bool regMissing = false, const char *regVal = nullptr) : ptr (nullptr) {
|
||||
Game::instance ().addNewCvar (name, initval, "", false, 0.0f, 0.0f, type, regMissing, regVal, this);
|
||||
}
|
||||
|
||||
ConVar (const char *name, const char *initval, const char *info, bool bounded = true, float min = 0.0f, float max = 1.0f, int32 type = Var::NoServer, bool regMissing = false, const char *regVal = nullptr) : ptr (nullptr) {
|
||||
ConVar (const char *name, const char *initval, const char *info, bool bounded = true, float min = 0.0f, float max = 1.0f, int32_t type = Var::NoServer, bool regMissing = false, const char *regVal = nullptr) : ptr (nullptr) {
|
||||
Game::instance ().addNewCvar (name, initval, info, bounded, min, max, type, regMissing, regVal, this);
|
||||
}
|
||||
|
||||
|
|
@ -505,8 +505,8 @@ public:
|
|||
}
|
||||
|
||||
public:
|
||||
static inline uint16 fu16 (float value, float scale) {
|
||||
return cr::clamp <uint16> (static_cast <uint16> (value * cr::bit (static_cast <short> (scale))), 0, USHRT_MAX);
|
||||
static inline uint16_t fu16 (float value, float scale) {
|
||||
return cr::clamp <uint16_t> (static_cast <uint16_t> (value * cr::bit (static_cast <short> (scale))), 0, USHRT_MAX);
|
||||
}
|
||||
|
||||
static inline short fs16 (float value, float scale) {
|
||||
|
|
@ -517,7 +517,7 @@ public:
|
|||
class LightMeasure final : public Singleton <LightMeasure> {
|
||||
private:
|
||||
lightstyle_t m_lightstyle[MAX_LIGHTSTYLES] {};
|
||||
uint32 m_lightstyleValue[MAX_LIGHTSTYLEVALUE] {};
|
||||
uint32_t m_lightstyleValue[MAX_LIGHTSTYLEVALUE] {};
|
||||
bool m_doAnimation = false;
|
||||
|
||||
Color m_point;
|
||||
|
|
@ -563,11 +563,11 @@ public:
|
|||
|
||||
// simple handler for parsing and rewriting queries (fake queries)
|
||||
class QueryBuffer {
|
||||
SmallArray <uint8> m_buffer {};
|
||||
SmallArray <uint8_t> m_buffer {};
|
||||
size_t m_cursor {};
|
||||
|
||||
public:
|
||||
QueryBuffer (const uint8 *msg, size_t length, size_t shift) : m_cursor (0) {
|
||||
QueryBuffer (const uint8_t *msg, size_t length, size_t shift) : m_cursor (0) {
|
||||
m_buffer.insert (0, msg, length);
|
||||
m_cursor += shift;
|
||||
}
|
||||
|
|
@ -630,7 +630,7 @@ public:
|
|||
}
|
||||
|
||||
public:
|
||||
Twin <const uint8 *, size_t> data () {
|
||||
Twin <const uint8_t *, size_t> data () {
|
||||
return { m_buffer.data (), m_buffer.length () };
|
||||
}
|
||||
};
|
||||
|
|
|
|||
76
inc/graph.h
76
inc/graph.h
|
|
@ -25,7 +25,7 @@ CR_DECLARE_SCOPED_ENUM (NodeFlag,
|
|||
)
|
||||
|
||||
// defines for node connection flags field (16 bits are available)
|
||||
CR_DECLARE_SCOPED_ENUM_TYPE (PathFlag, uint16,
|
||||
CR_DECLARE_SCOPED_ENUM_TYPE (PathFlag, uint16_t,
|
||||
Jump = cr::bit (0) // must jump for this connection
|
||||
)
|
||||
|
||||
|
|
@ -112,59 +112,59 @@ struct Route {
|
|||
|
||||
// general stprage header information structure
|
||||
struct StorageHeader {
|
||||
int32 magic;
|
||||
int32 version;
|
||||
int32 options;
|
||||
int32 length;
|
||||
int32 compressed;
|
||||
int32 uncompressed;
|
||||
int32_t magic;
|
||||
int32_t version;
|
||||
int32_t options;
|
||||
int32_t length;
|
||||
int32_t compressed;
|
||||
int32_t uncompressed;
|
||||
};
|
||||
|
||||
// extension header for graph information
|
||||
struct ExtenHeader {
|
||||
char author[32]; // original author of graph
|
||||
int32 mapSize; // bsp size for checksumming map consistency
|
||||
int32_t mapSize; // bsp size for checksumming map consistency
|
||||
char modified[32]; // by whom modified
|
||||
};
|
||||
|
||||
// general waypoint header information structure
|
||||
struct PODGraphHeader {
|
||||
char header[8];
|
||||
int32 fileVersion;
|
||||
int32 pointNumber;
|
||||
int32_t fileVersion;
|
||||
int32_t pointNumber;
|
||||
char mapName[32];
|
||||
char author[32];
|
||||
};
|
||||
|
||||
// floyd-warshall matrices
|
||||
struct Matrix {
|
||||
int16 dist;
|
||||
int16 index;
|
||||
int16_t dist;
|
||||
int16_t index;
|
||||
};
|
||||
|
||||
// experience data hold in memory while playing
|
||||
struct Practice {
|
||||
int16 damage[kGameTeamNum];
|
||||
int16 index[kGameTeamNum];
|
||||
int16 value[kGameTeamNum];
|
||||
int16_t damage[kGameTeamNum];
|
||||
int16_t index[kGameTeamNum];
|
||||
int16_t value[kGameTeamNum];
|
||||
};
|
||||
|
||||
// defines linked waypoints
|
||||
struct PathLink {
|
||||
Vector velocity;
|
||||
int32 distance;
|
||||
uint16 flags;
|
||||
int16 index;
|
||||
int32_t distance;
|
||||
uint16_t flags;
|
||||
int16_t index;
|
||||
};
|
||||
|
||||
// defines visibility count
|
||||
struct PathVis {
|
||||
uint16 stand, crouch;
|
||||
uint16_t stand, crouch;
|
||||
};
|
||||
|
||||
// define graph path structure for yapb
|
||||
struct Path {
|
||||
int32 number, flags;
|
||||
int32_t number, flags;
|
||||
Vector origin, start, end;
|
||||
float radius, light, display;
|
||||
PathLink links[kMaxNodeLinks];
|
||||
|
|
@ -173,13 +173,13 @@ struct Path {
|
|||
|
||||
// define waypoint structure for podbot (will convert on load)
|
||||
struct PODPath {
|
||||
int32 number, flags;
|
||||
int32_t number, flags;
|
||||
Vector origin;
|
||||
float radius, csx, csy, cex, cey;
|
||||
int16 index[kMaxNodeLinks];
|
||||
uint16 conflags[kMaxNodeLinks];
|
||||
int16_t index[kMaxNodeLinks];
|
||||
uint16_t conflags[kMaxNodeLinks];
|
||||
Vector velocity[kMaxNodeLinks];
|
||||
int32 distance[kMaxNodeLinks];
|
||||
int32_t distance[kMaxNodeLinks];
|
||||
PathVis vis;
|
||||
};
|
||||
|
||||
|
|
@ -189,26 +189,26 @@ private:
|
|||
size_t m_cursor {};
|
||||
size_t m_length {};
|
||||
|
||||
UniquePtr <int32[]> m_path {};
|
||||
UniquePtr <int32_t[]> m_path {};
|
||||
|
||||
public:
|
||||
explicit PathWalk () = default;
|
||||
~PathWalk () = default;
|
||||
|
||||
public:
|
||||
int32 &next () {
|
||||
int32_t &next () {
|
||||
return at (1);
|
||||
}
|
||||
|
||||
int32 &first () {
|
||||
int32_t &first () {
|
||||
return at (0);
|
||||
}
|
||||
|
||||
int32 &last () {
|
||||
int32_t &last () {
|
||||
return at (length () - 1);
|
||||
}
|
||||
|
||||
int32 &at (size_t index) {
|
||||
int32_t &at (size_t index) {
|
||||
return m_path[m_cursor + index];
|
||||
}
|
||||
|
||||
|
|
@ -237,7 +237,7 @@ public:
|
|||
return !length ();
|
||||
}
|
||||
|
||||
void add (int32 node) {
|
||||
void add (int32_t node) {
|
||||
m_path[m_length++] = node;
|
||||
}
|
||||
|
||||
|
|
@ -249,7 +249,7 @@ public:
|
|||
}
|
||||
|
||||
void init (size_t length) {
|
||||
m_path = cr::makeUnique <int32 []> (length);
|
||||
m_path = cr::makeUnique <int32_t []> (length);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -297,11 +297,11 @@ private:
|
|||
IntArray m_rescuePoints {};
|
||||
IntArray m_visitedGoals {};
|
||||
|
||||
SmallArray <int32> m_buckets[kMaxBucketsInsidePos][kMaxBucketsInsidePos][kMaxBucketsInsidePos];
|
||||
SmallArray <int32_t> m_buckets[kMaxBucketsInsidePos][kMaxBucketsInsidePos][kMaxBucketsInsidePos];
|
||||
SmallArray <Matrix> m_matrix {};
|
||||
SmallArray <Practice> m_practice {};
|
||||
SmallArray <Path> m_paths {};
|
||||
SmallArray <uint8> m_vistable {};
|
||||
SmallArray <uint8_t> m_vistable {};
|
||||
|
||||
String m_graphAuthor {};
|
||||
String m_graphModified {};
|
||||
|
|
@ -346,7 +346,7 @@ public:
|
|||
bool canDownload ();
|
||||
|
||||
template <typename U> bool saveStorage (StringRef ext, StringRef name, StorageOption options, StorageVersion version, const SmallArray <U> &data, ExtenHeader *exten);
|
||||
template <typename U> bool loadStorage (StringRef ext, StringRef name, StorageOption options, StorageVersion version, SmallArray <U> &data, ExtenHeader *exten, int32 *outOptions);
|
||||
template <typename U> bool loadStorage (StringRef ext, StringRef name, StorageOption options, StorageVersion version, SmallArray <U> &data, ExtenHeader *exten, int32_t *outOptions);
|
||||
template <typename ...Args> bool raiseLoadingError (bool isGraph, MemFile &file, const char *fmt, Args &&...args);
|
||||
|
||||
void saveOldFormat ();
|
||||
|
|
@ -396,7 +396,7 @@ public:
|
|||
|
||||
Bucket locateBucket (const Vector &pos);
|
||||
IntArray searchRadius (float radius, const Vector &origin, int maxCount = -1);
|
||||
const SmallArray <int32> &getNodesInBucket (const Vector &pos);
|
||||
const SmallArray <int32_t> &getNodesInBucket (const Vector &pos);
|
||||
|
||||
public:
|
||||
size_t getMaxRouteLength () const {
|
||||
|
|
@ -446,12 +446,12 @@ public:
|
|||
|
||||
// check nodes range
|
||||
bool exists (int index) const {
|
||||
return index >= 0 && index < static_cast <int> (m_paths.length ());
|
||||
return index >= 0 && index < length ();
|
||||
}
|
||||
|
||||
// get real nodes num
|
||||
int32 length () const {
|
||||
return m_paths.length <int32> ();
|
||||
int32_t length () const {
|
||||
return m_paths.length <int32_t> ();
|
||||
}
|
||||
|
||||
// check if has editor
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ private:
|
|||
|
||||
public:
|
||||
float MaxView = 4096.0f;
|
||||
float MinView = 5.0f;
|
||||
float MinView = 2.0f;
|
||||
|
||||
public:
|
||||
float farHeight; // height of the far frustum
|
||||
|
|
@ -108,6 +108,7 @@ public:
|
|||
|
||||
int getHumansCount (bool ignoreSpectators = false);
|
||||
int getAliveHumansCount ();
|
||||
int getPlayerPriority (edict_t *ent);
|
||||
|
||||
float getConnectTime (StringRef name, float original);
|
||||
float getAverageTeamKPD (bool calcForBots);
|
||||
|
|
@ -174,12 +175,12 @@ public:
|
|||
return m_economicsGood[team];
|
||||
}
|
||||
|
||||
int32 getLastWinner () const {
|
||||
int32_t getLastWinner () const {
|
||||
return m_lastWinner;
|
||||
}
|
||||
|
||||
int32 getBotCount () {
|
||||
return m_bots.length <int32> ();
|
||||
int32_t getBotCount () {
|
||||
return m_bots.length <int32_t> ();
|
||||
}
|
||||
|
||||
// get the list of filters
|
||||
|
|
|
|||
|
|
@ -65,27 +65,27 @@ CR_DECLARE_SCOPED_ENUM (StatusIconCache,
|
|||
class MessageDispatcher final : public Singleton <MessageDispatcher> {
|
||||
private:
|
||||
using MsgFunc = void (MessageDispatcher::*) ();
|
||||
using MsgHash = Hash <int32>;
|
||||
using MsgHash = Hash <int32_t>;
|
||||
|
||||
private:
|
||||
struct Args {
|
||||
union {
|
||||
float float_;
|
||||
int32 long_;
|
||||
int32_t long_;
|
||||
const char *chars_;
|
||||
};
|
||||
|
||||
public:
|
||||
Args (float value) : float_ (value) { }
|
||||
Args (int32 value) : long_ (value) { }
|
||||
Args (int32_t value) : long_ (value) { }
|
||||
Args (const char *value) : chars_ (value) { }
|
||||
};
|
||||
|
||||
private:
|
||||
HashMap <String, int32> m_textMsgCache {}; // cache strings for faster access for textmsg
|
||||
HashMap <String, int32> m_showMenuCache {}; // cache for the showmenu message
|
||||
HashMap <String, int32> m_statusIconCache {}; // cache for status icon message
|
||||
HashMap <String, int32> m_teamInfoCache {}; // cache for teaminfo message
|
||||
HashMap <String, int32_t> m_textMsgCache {}; // cache strings for faster access for textmsg
|
||||
HashMap <String, int32_t> m_showMenuCache {}; // cache for the showmenu message
|
||||
HashMap <String, int32_t> m_statusIconCache {}; // cache for status icon message
|
||||
HashMap <String, int32_t> m_teamInfoCache {}; // cache for teaminfo message
|
||||
|
||||
private:
|
||||
Bot *m_bot {}; // owner of a message
|
||||
|
|
@ -94,9 +94,9 @@ private:
|
|||
SmallArray <Args> m_args {}; // args collected from write* functions
|
||||
|
||||
HashMap <String, NetMsg> m_wanted {}; // wanted messages
|
||||
HashMap <int32, NetMsg> m_reverseMap {}; // maps engine message id to our message id
|
||||
HashMap <int32_t, NetMsg> m_reverseMap {}; // maps engine message id to our message id
|
||||
|
||||
HashMap <NetMsg, int32, MsgHash> m_maps {}; // maps our message to id to engine message id
|
||||
HashMap <NetMsg, int32_t, MsgHash> m_maps {}; // maps our message to id to engine message id
|
||||
HashMap <NetMsg, MsgFunc, MsgHash> m_handlers {}; // maps our message id to handler function
|
||||
|
||||
private:
|
||||
|
|
@ -122,17 +122,17 @@ private:
|
|||
void netMsgScoreAttrib ();
|
||||
|
||||
private:
|
||||
Bot *pickBot (int32 index);
|
||||
Bot *pickBot (int32_t index);
|
||||
|
||||
public:
|
||||
MessageDispatcher ();
|
||||
~MessageDispatcher () = default;
|
||||
|
||||
public:
|
||||
int32 add (StringRef name, int32 id);
|
||||
int32 id (NetMsg msg);
|
||||
int32_t add (StringRef name, int32_t id);
|
||||
int32_t id (NetMsg msg);
|
||||
|
||||
void start (edict_t *ent, int32 type);
|
||||
void start (edict_t *ent, int32_t type);
|
||||
void stop ();
|
||||
void ensureMessages ();
|
||||
|
||||
|
|
|
|||
40
inc/sounds.h
Normal file
40
inc/sounds.h
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
//
|
||||
// YaPB - Counter-Strike Bot based on PODBot by Markus Klinge.
|
||||
// Copyright © 2004-2023 YaPB Project <yapb@jeefo.net>.
|
||||
//
|
||||
// SPDX-License-Identifier: MIT
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
// noise types
|
||||
CR_DECLARE_SCOPED_ENUM (Noise,
|
||||
NeedHandle = cr::bit (0),
|
||||
HitFall = cr::bit (1),
|
||||
Pickup = cr::bit (2),
|
||||
Zoom = cr::bit (3),
|
||||
Ammo = cr::bit (4),
|
||||
Hostage = cr::bit (5),
|
||||
Broke = cr::bit (6),
|
||||
Door = cr::bit (7),
|
||||
Defuse = cr::bit (8)
|
||||
)
|
||||
|
||||
class BotSounds final : public Singleton <BotSounds> {
|
||||
private:
|
||||
HashMap <String, int32_t> m_noiseCache {};
|
||||
|
||||
public:
|
||||
BotSounds ();
|
||||
~BotSounds () = default;
|
||||
|
||||
public:
|
||||
// attaches sound to client struct
|
||||
void listenNoise (edict_t *ent, StringRef sample, float volume);
|
||||
|
||||
// simulate sound for players
|
||||
void simulateNoise (int playerIndex);
|
||||
};
|
||||
|
||||
// explose global
|
||||
CR_EXPOSE_GLOBAL_SINGLETON (BotSounds, sounds);
|
||||
|
|
@ -7,18 +7,6 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
// noise types
|
||||
CR_DECLARE_SCOPED_ENUM (Noise,
|
||||
NeedHandle = cr::bit (0),
|
||||
HitFall = cr::bit (1),
|
||||
Pickup = cr::bit (2),
|
||||
Zoom = cr::bit (3),
|
||||
Ammo = cr::bit (4),
|
||||
Hostage = cr::bit (5),
|
||||
Broke = cr::bit (6),
|
||||
Door = cr::bit (7)
|
||||
)
|
||||
|
||||
class BotSupport final : public Singleton <BotSupport> {
|
||||
private:
|
||||
bool m_needToSendWelcome {};
|
||||
|
|
@ -28,8 +16,7 @@ private:
|
|||
SmallArray <Client> m_clients {};
|
||||
SmallArray <Twin <String, String>> m_tags {};
|
||||
|
||||
HashMap <int32, String> m_weaponAlias {};
|
||||
HashMap <String, int32> m_noiseCache {};
|
||||
HashMap <int32_t, String> m_weaponAlias {};
|
||||
Detour <decltype (sendto)> m_sendToDetour { "ws2_32.dll", "sendto", sendto };
|
||||
|
||||
public:
|
||||
|
|
@ -41,7 +28,7 @@ public:
|
|||
void checkWelcome ();
|
||||
|
||||
// converts weapon id to alias name
|
||||
StringRef weaponIdToAlias (int32 id);
|
||||
StringRef weaponIdToAlias (int32_t id);
|
||||
|
||||
// check if origin is visible from the entity side
|
||||
bool isVisible (const Vector &origin, edict_t *ent);
|
||||
|
|
@ -73,12 +60,6 @@ public:
|
|||
// tracing decals for bots spraying logos
|
||||
void traceDecals (entvars_t *pev, TraceResult *trace, int logotypeIndex);
|
||||
|
||||
// attaches sound to client struct
|
||||
void listenNoise (edict_t *ent, StringRef sample, float volume);
|
||||
|
||||
// simulate sound for players
|
||||
void simulateNoise (int playerIndex);
|
||||
|
||||
// update stats on clients
|
||||
void updateClients ();
|
||||
|
||||
|
|
@ -153,7 +134,7 @@ public:
|
|||
}
|
||||
|
||||
public:
|
||||
static int32 CR_STDCALL sendTo (int socket, const void *message, size_t length, int flags, const struct sockaddr *dest, int destLength);
|
||||
static int32_t CR_STDCALL sendTo (int socket, const void *message, size_t length, int flags, const struct sockaddr *dest, int destLength);
|
||||
};
|
||||
|
||||
// explose global
|
||||
|
|
|
|||
75
inc/yapb.h
75
inc/yapb.h
|
|
@ -46,6 +46,7 @@ CR_DECLARE_SCOPED_ENUM (Task,
|
|||
Hide,
|
||||
Blind,
|
||||
Spraypaint,
|
||||
Max
|
||||
)
|
||||
|
||||
// bot menu ids
|
||||
|
|
@ -349,7 +350,7 @@ CR_DECLARE_SCOPED_ENUM (Reload,
|
|||
)
|
||||
|
||||
// collision probes
|
||||
CR_DECLARE_SCOPED_ENUM (CollisionProbe, uint32,
|
||||
CR_DECLARE_SCOPED_ENUM (CollisionProbe, uint32_t,
|
||||
Jump = cr::bit (0), // probe jump when colliding
|
||||
Duck = cr::bit (1), // probe duck when colliding
|
||||
Strafe = cr::bit (2) // probe strafing when colliding
|
||||
|
|
@ -367,7 +368,7 @@ CR_DECLARE_SCOPED_ENUM (BotMsg,
|
|||
)
|
||||
|
||||
// sensing states
|
||||
CR_DECLARE_SCOPED_ENUM_TYPE (Sense, uint32,
|
||||
CR_DECLARE_SCOPED_ENUM_TYPE (Sense, uint32_t,
|
||||
SeeingEnemy = cr::bit (0), // seeing an enemy
|
||||
HearingEnemy = cr::bit (1), // hearing an enemy
|
||||
SuspectEnemy = cr::bit (2), // suspect enemy behind obstacle
|
||||
|
|
@ -378,7 +379,7 @@ CR_DECLARE_SCOPED_ENUM_TYPE (Sense, uint32,
|
|||
)
|
||||
|
||||
// positions to aim at
|
||||
CR_DECLARE_SCOPED_ENUM_TYPE (AimFlags, uint32,
|
||||
CR_DECLARE_SCOPED_ENUM_TYPE (AimFlags, uint32_t,
|
||||
Nav = cr::bit (0), // aim at nav point
|
||||
Camp = cr::bit (1), // aim at camp vector
|
||||
PredictPath = cr::bit (2), // aim at predicted path
|
||||
|
|
@ -445,11 +446,11 @@ namespace TaskPri {
|
|||
// storage file magic
|
||||
constexpr char kPodbotMagic[8] = "PODWAY!";
|
||||
|
||||
constexpr int32 kStorageMagic = 0x59415042; // storage magic for yapb-data files
|
||||
constexpr int32 kStorageMagicUB = 0x544f4255; //support also the fork format (merged back into yapb)
|
||||
constexpr int32_t kStorageMagic = 0x59415042; // storage magic for yapb-data files
|
||||
constexpr int32_t kStorageMagicUB = 0x544f4255; //support also the fork format (merged back into yapb)
|
||||
|
||||
constexpr float kInfiniteDistance = 9999999.0f;
|
||||
constexpr float kGrenadeCheckTime = 2.15f;
|
||||
constexpr float kGrenadeCheckTime = 0.6f;
|
||||
constexpr float kSprayDistance = 260.0f;
|
||||
constexpr float kDoubleSprayDistance = kSprayDistance * 2;
|
||||
constexpr float kMaxChatterRepeatInterval = 99.0f;
|
||||
|
|
@ -610,12 +611,12 @@ public:
|
|||
friend class BotManager;
|
||||
|
||||
private:
|
||||
uint32 m_states {}; // sensing bitstates
|
||||
uint32 m_collideMoves[kMaxCollideMoves] {}; // sorted array of movements
|
||||
uint32 m_collisionProbeBits {}; // bits of possible collision moves
|
||||
uint32 m_collStateIndex {}; // index into collide moves
|
||||
uint32 m_aimFlags {}; // aiming conditions
|
||||
uint32 m_currentTravelFlags {}; // connection flags like jumping
|
||||
uint32_t m_states {}; // sensing bitstates
|
||||
uint32_t m_collideMoves[kMaxCollideMoves] {}; // sorted array of movements
|
||||
uint32_t m_collisionProbeBits {}; // bits of possible collision moves
|
||||
uint32_t m_collStateIndex {}; // index into collide moves
|
||||
uint32_t m_aimFlags {}; // aiming conditions
|
||||
uint32_t m_currentTravelFlags {}; // connection flags like jumping
|
||||
|
||||
int m_traceSkip[TraceChannel::Num] {}; // trace need to be skipped?
|
||||
int m_messageQueue[32] {}; // stack for messages
|
||||
|
|
@ -688,6 +689,7 @@ private:
|
|||
float m_playServerTime {}; // time bot spent in the game
|
||||
float m_changeViewTime {}; // timestamp to change look at while at freezetime
|
||||
float m_breakableTime {}; // breakeble acquired time
|
||||
float m_jumpDistance {}; // last jump distance
|
||||
|
||||
bool m_moveToGoal {}; // bot currently moving to goal??
|
||||
bool m_isStuck {}; // bot is stuck
|
||||
|
|
@ -706,6 +708,7 @@ private:
|
|||
bool m_checkTerrain {}; // check for terrain
|
||||
bool m_moveToC4 {}; // ct is moving to bomb
|
||||
bool m_grenadeRequested {}; // bot requested change to grenade
|
||||
bool m_needToSendWelcomeChat {}; // bot needs to greet people on server?
|
||||
|
||||
Pickup m_pickupType {}; // type of entity which needs to be used/picked up
|
||||
PathWalk m_pathWalk {}; // pointer to current node from path
|
||||
|
|
@ -713,7 +716,7 @@ private:
|
|||
Fight m_fightStyle {}; // combat style to use
|
||||
CollisionState m_collisionState {}; // collision State
|
||||
FindPath m_pathType {}; // which pathfinder to use
|
||||
uint8 m_enemyParts {}; // visibility flags
|
||||
uint8_t m_enemyParts {}; // visibility flags
|
||||
TraceResult m_lastTrace[TraceChannel::Num] {}; // last trace result
|
||||
|
||||
edict_t *m_pickupItem {}; // pointer to entity of item to use/pickup
|
||||
|
|
@ -723,6 +726,7 @@ private:
|
|||
edict_t *m_lastBreakable {}; // last acquired breakable
|
||||
edict_t *m_targetEntity {}; // the entity that the bot is trying to reach
|
||||
edict_t *m_avoidGrenade {}; // pointer to grenade entity to avoid
|
||||
edict_t *m_hindrance {}; // the hidrance
|
||||
|
||||
Vector m_liftTravelPos {}; // lift travel position
|
||||
Vector m_moveAngles {}; // bot move angles
|
||||
|
|
@ -744,7 +748,7 @@ private:
|
|||
Array <edict_t *> m_ignoredBreakable {}; // list of ignored breakables
|
||||
Array <edict_t *> m_hostages {}; // pointer to used hostage entities
|
||||
Array <Route> m_routes {}; // pointer
|
||||
Array <int32> m_goalHistory {}; // history of selected goals
|
||||
Array <int32_t> m_nodeHistory {}; // history of selected goals
|
||||
|
||||
BinaryHeap <RouteTwin> m_routeQue {};
|
||||
Path *m_path {}; // pointer to the current path node
|
||||
|
|
@ -753,7 +757,7 @@ private:
|
|||
|
||||
private:
|
||||
int pickBestWeapon (int *vec, int count, int moneySave);
|
||||
int findCampingDirection ();
|
||||
int getRandomCampDir ();
|
||||
int findAimingNode (const Vector &to, int &pathLength);
|
||||
int findNearestNode ();
|
||||
int findBombNode ();
|
||||
|
|
@ -766,12 +770,12 @@ private:
|
|||
int bestSecondaryCarried ();
|
||||
int bestGrenadeCarried ();
|
||||
int bestWeaponCarried ();
|
||||
int changePointIndex (int index);
|
||||
int changeNodeIndex (int index);
|
||||
int numEnemiesNear (const Vector &origin, float radius);
|
||||
int numFriendsNear (const Vector &origin, float radius);
|
||||
|
||||
float getBombTimeleft ();
|
||||
float getReachTime ();
|
||||
float getEstimatedNodeReachTime ();
|
||||
float isInFOV (const Vector &dest);
|
||||
float getShiftSpeed ();
|
||||
float getEnemyBodyOffsetCorrection (float distance);
|
||||
|
|
@ -795,7 +799,6 @@ private:
|
|||
bool isInViewCone (const Vector &origin);
|
||||
bool checkBodyParts (edict_t *target);
|
||||
bool seesEnemy (edict_t *player, bool ignoreFOV = false);
|
||||
bool doPlayerAvoidance (const Vector &normal);
|
||||
bool hasActiveGoal ();
|
||||
bool advanceMovement ();
|
||||
bool isBombDefusing (const Vector &bombOrigin);
|
||||
|
|
@ -828,6 +831,8 @@ private:
|
|||
bool updateLiftStates ();
|
||||
bool canRunHeavyWeight ();
|
||||
|
||||
void doPlayerAvoidance (const Vector &normal);
|
||||
void selectCampButtons (int index);
|
||||
void markStale ();
|
||||
void instantChatter (int type);
|
||||
void update ();
|
||||
|
|
@ -851,10 +856,10 @@ private:
|
|||
void updateHearing ();
|
||||
void postprocessGoals (const IntArray &goals, int result[]);
|
||||
void updatePickups ();
|
||||
void ensureEntitiesClear ();
|
||||
void checkTerrain (float movedDistance, const Vector &dirNormal);
|
||||
void checkDarkness ();
|
||||
void checkParachute ();
|
||||
void getCampDirection (Vector *dest);
|
||||
void updatePracticeValue (int damage);
|
||||
void updatePracticeDamage (edict_t *attacker, int damage);
|
||||
void findShortestPath (int srcIndex, int destIndex);
|
||||
|
|
@ -880,13 +885,15 @@ private:
|
|||
void focusEnemy ();
|
||||
void selectBestWeapon ();
|
||||
void selectSecondary ();
|
||||
void selectWeaponByName (StringRef name);
|
||||
void selectWeaponById (int id);
|
||||
void selectWeaponByIndex (int index);
|
||||
|
||||
void completeTask ();
|
||||
void tasks ();
|
||||
void executeTasks ();
|
||||
void trackEnemies ();
|
||||
void choiceFreezetimeEntity ();
|
||||
void logicDuringFreezetime ();
|
||||
void translateInput ();
|
||||
void moveToGoal ();
|
||||
|
||||
void normal_ ();
|
||||
void spraypaint_ ();
|
||||
|
|
@ -911,15 +918,16 @@ private:
|
|||
|
||||
edict_t *lookupButton (const char *target);
|
||||
edict_t *lookupBreakable ();
|
||||
edict_t *correctGrenadeVelocity (const char *model);
|
||||
edict_t *setCorrectGrenadeVelocity (const char *model);
|
||||
|
||||
const Vector &getEnemyBodyOffset ();
|
||||
Vector calcThrow (const Vector &start, const Vector &stop);
|
||||
Vector calcToss (const Vector &start, const Vector &stop);
|
||||
Vector isBombAudible ();
|
||||
Vector getBodyOffsetError (float distance);
|
||||
Vector getCampDirection (const Vector &dest);
|
||||
|
||||
uint8 computeMsec ();
|
||||
uint8_t computeMsec ();
|
||||
|
||||
private:
|
||||
bool isOnLadder () const {
|
||||
|
|
@ -927,7 +935,7 @@ private:
|
|||
}
|
||||
|
||||
bool isOnFloor () const {
|
||||
return (pev->flags & (FL_ONGROUND | FL_PARTIALGROUND)) != 0;
|
||||
return !!(pev->flags & (FL_ONGROUND | FL_PARTIALGROUND));
|
||||
}
|
||||
|
||||
bool isInWater () const {
|
||||
|
|
@ -938,6 +946,10 @@ private:
|
|||
return (m_pathFlags & NodeFlag::Narrow);
|
||||
}
|
||||
|
||||
void dropCurrentWeapon () {
|
||||
issueCommand ("drop");
|
||||
}
|
||||
|
||||
public:
|
||||
entvars_t *pev {};
|
||||
|
||||
|
|
@ -1044,7 +1056,7 @@ public:
|
|||
BurstMode m_weaponBurstMode {}; // bot using burst mode? (famas/glock18, but also silencer mode)
|
||||
Personality m_personality {}; // bots type
|
||||
Array <BotTask> m_tasks {};
|
||||
Deque <int32> m_msgQueue {};
|
||||
Deque <int32_t> m_msgQueue {};
|
||||
|
||||
public:
|
||||
Bot (edict_t *bot, int difficulty, int personality, int team, int skin);
|
||||
|
|
@ -1097,7 +1109,7 @@ public:
|
|||
bool hasSecondaryWeapon ();
|
||||
bool hasShield ();
|
||||
bool isShieldDrawn ();
|
||||
bool findBestNearestNode ();
|
||||
bool findNextBestNode ();
|
||||
bool seesEntity (const Vector &dest, bool fromBody = false);
|
||||
bool canSkipNextTrace (TraceChannel channel);
|
||||
|
||||
|
|
@ -1105,7 +1117,6 @@ public:
|
|||
int getAmmo (int id);
|
||||
int getNearestToPlantedBomb ();
|
||||
|
||||
float getFrameInterval ();
|
||||
float getConnectionTime ();
|
||||
BotTask *getTask ();
|
||||
|
||||
|
|
@ -1114,7 +1125,9 @@ public:
|
|||
return m_ammoInClip[m_currentWeapon];
|
||||
}
|
||||
|
||||
bool isLowOnAmmo (const int index, const float factor) const;
|
||||
bool isDucking () const {
|
||||
return !!(pev->flags & FL_DUCKING);
|
||||
}
|
||||
|
||||
Vector getCenter () const {
|
||||
return (pev->absmax + pev->absmin) * 0.5;
|
||||
|
|
@ -1157,6 +1170,9 @@ public:
|
|||
return m_lastTrace[channel];
|
||||
}
|
||||
|
||||
// is low on admmo on index?
|
||||
bool isLowOnAmmo (const int index, const float factor) const;
|
||||
|
||||
// prints debug message
|
||||
template <typename ...Args> void debugMsg (const char *fmt, Args &&...args) {
|
||||
debugMsgInternal (strings.format (fmt, cr::forward <Args> (args)...));
|
||||
|
|
@ -1168,6 +1184,7 @@ public:
|
|||
|
||||
#include "config.h"
|
||||
#include "support.h"
|
||||
#include "sounds.h"
|
||||
#include "message.h"
|
||||
#include "engine.h"
|
||||
#include "manager.h"
|
||||
|
|
|
|||
|
|
@ -230,6 +230,7 @@ sources = files (
|
|||
'src/module.cpp',
|
||||
'src/message.cpp',
|
||||
'src/navigate.cpp',
|
||||
'src/sounds.cpp',
|
||||
'src/support.cpp'
|
||||
)
|
||||
|
||||
|
|
|
|||
858
src/botlib.cpp
858
src/botlib.cpp
File diff suppressed because it is too large
Load diff
|
|
@ -54,7 +54,7 @@ void BotSupport::addChatErrors (String &line) {
|
|||
if (rg.chance (8) && strcmp (cv_language.str (), "en") == 0) {
|
||||
line.lowercase ();
|
||||
}
|
||||
auto length = static_cast <int32> (line.length ());
|
||||
auto length = static_cast <int32_t> (line.length ());
|
||||
|
||||
if (length > 15) {
|
||||
auto percentile = length / 2;
|
||||
|
|
|
|||
504
src/combat.cpp
504
src/combat.cpp
|
|
@ -14,6 +14,7 @@ ConVar cv_check_enemy_invincibility ("yb_check_enemy_invincibility", "0", "Enabl
|
|||
ConVar cv_stab_close_enemies ("yb_stab_close_enemies", "1", "Enables or disables bot ability to stab the enemy with knife if bot is in good condition.");
|
||||
|
||||
ConVar mp_friendlyfire ("mp_friendlyfire", nullptr, Var::GameRef);
|
||||
ConVar sv_gravity ("sv_gravity", nullptr, Var::GameRef);
|
||||
|
||||
int Bot::numFriendsNear (const Vector &origin, float radius) {
|
||||
int count = 0;
|
||||
|
|
@ -133,17 +134,15 @@ bool Bot::checkBodyParts (edict_t *target) {
|
|||
}
|
||||
|
||||
// check top of head
|
||||
if (util.isPlayer (target)) {
|
||||
spot.z += 25.0f;
|
||||
game.testLine (eyes, spot, TraceIgnore::Everything, self, &result);
|
||||
spot.z += 25.0f;
|
||||
game.testLine (eyes, spot, TraceIgnore::Everything, self, &result);
|
||||
|
||||
if (result.flFraction >= 1.0f) {
|
||||
m_enemyParts |= Visibility::Head;
|
||||
m_enemyOrigin = result.vecEndPos;
|
||||
}
|
||||
if (result.flFraction >= 1.0f) {
|
||||
m_enemyParts |= Visibility::Head;
|
||||
m_enemyOrigin = result.vecEndPos;
|
||||
}
|
||||
|
||||
if (m_enemyParts != 0) {
|
||||
if (m_enemyParts != Visibility::None) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -197,10 +196,6 @@ bool Bot::seesEnemy (edict_t *player, bool ignoreFOV) {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (m_difficulty == Difficulty::Expert && m_kpdRatio < 1.5f && util.isPlayer (pev->dmg_inflictor) && game.getTeam (pev->dmg_inflictor) != m_team) {
|
||||
ignoreFOV = true;
|
||||
}
|
||||
|
||||
if ((ignoreFOV || isInViewCone (player->v.origin)) && isEnemyInFrustum (player) && checkBodyParts (player)) {
|
||||
m_seeEnemyTime = game.time ();
|
||||
m_lastEnemy = player;
|
||||
|
|
@ -276,7 +271,7 @@ bool Bot::lookupEnemies () {
|
|||
float scaleFactor = (1.0f / calculateScaleFactor (intresting));
|
||||
float distance = intresting->v.origin.distanceSq (pev->origin) * scaleFactor;
|
||||
|
||||
if (distance < nearestDistance) {
|
||||
if (distance * 0.65f < nearestDistance) {
|
||||
nearestDistance = distance;
|
||||
newEnemy = intresting;
|
||||
}
|
||||
|
|
@ -309,7 +304,7 @@ bool Bot::lookupEnemies () {
|
|||
}
|
||||
float distance = player->v.origin.distanceSq (pev->origin);
|
||||
|
||||
if (distance < nearestDistance) {
|
||||
if (distance * 0.65f < nearestDistance) {
|
||||
nearestDistance = distance;
|
||||
newEnemy = player;
|
||||
|
||||
|
|
@ -320,7 +315,7 @@ bool Bot::lookupEnemies () {
|
|||
}
|
||||
}
|
||||
}
|
||||
m_enemyUpdateTime = cr::clamp (game.time () + getFrameInterval () * 25.0f, 0.5f, 0.75f);
|
||||
m_enemyUpdateTime = cr::clamp (game.time () + m_frameInterval * 25.0f, 0.5f, 0.75f);
|
||||
|
||||
if (game.isNullEntity (newEnemy) && !game.isNullEntity (shieldEnemy)) {
|
||||
newEnemy = shieldEnemy;
|
||||
|
|
@ -349,18 +344,7 @@ bool Bot::lookupEnemies () {
|
|||
pushRadioMessage (Radio::EnemySpotted);
|
||||
}
|
||||
m_targetEntity = nullptr; // stop following when we see an enemy...
|
||||
|
||||
if (m_difficulty == Difficulty::Expert) {
|
||||
m_enemySurpriseTime = m_actualReactionTime * 0.5f;
|
||||
}
|
||||
else {
|
||||
m_enemySurpriseTime = m_actualReactionTime;
|
||||
}
|
||||
|
||||
if (usesSniper ()) {
|
||||
m_enemySurpriseTime *= 0.5f;
|
||||
}
|
||||
m_enemySurpriseTime += game.time ();
|
||||
m_enemySurpriseTime = game.time () + m_actualReactionTime;
|
||||
|
||||
// zero out reaction time
|
||||
m_actualReactionTime = 0.0f;
|
||||
|
|
@ -461,7 +445,7 @@ Vector Bot::getBodyOffsetError (float distance) {
|
|||
}
|
||||
|
||||
if (m_aimErrorTime < game.time ()) {
|
||||
const float error = distance / (cr::clamp (static_cast <float> (m_difficulty), 1.0f, 3.0f) * 1000.0f);
|
||||
const float error = distance / (cr::clamp (static_cast <float> (m_difficulty), 1.0f, 4.0f) * 1000.0f);
|
||||
auto &maxs = m_enemy->v.maxs, &mins = m_enemy->v.mins;
|
||||
|
||||
m_aimLastError = Vector (rg.get (mins.x * error, maxs.x * error), rg.get (mins.y * error, maxs.y * error), rg.get (mins.z * error, maxs.z * error));
|
||||
|
|
@ -474,10 +458,6 @@ const Vector &Bot::getEnemyBodyOffset () {
|
|||
// the purpose of this function, is to make bot aiming not so ideal. it's mutate m_enemyOrigin enemy vector
|
||||
// returned from visibility check function.
|
||||
|
||||
const auto headOffset = [] (edict_t *e) {
|
||||
return e->v.absmin.z + e->v.size.z * 0.81f;
|
||||
};
|
||||
|
||||
// if no visibility data, use last one
|
||||
if (!m_enemyParts) {
|
||||
return m_enemyOrigin;
|
||||
|
|
@ -485,7 +465,7 @@ const Vector &Bot::getEnemyBodyOffset () {
|
|||
float distance = m_enemy->v.origin.distance (pev->origin);
|
||||
|
||||
// do not aim at head, at long distance (only if not using sniper weapon)
|
||||
if ((m_enemyParts & Visibility::Body) && !usesSniper () && distance > (m_difficulty > Difficulty::Normal ? 2000.0f : 1000.0f)) {
|
||||
if ((m_enemyParts & Visibility::Body) && !usesSniper () && distance > (m_difficulty >= Difficulty::Normal ? 2000.0f : 1000.0f)) {
|
||||
m_enemyParts &= ~Visibility::Head;
|
||||
}
|
||||
|
||||
|
|
@ -493,18 +473,21 @@ const Vector &Bot::getEnemyBodyOffset () {
|
|||
else if (distance < 800.0f && usesSniper ()) {
|
||||
m_enemyParts &= ~Visibility::Head;
|
||||
}
|
||||
else if (distance < kSprayDistance / 2 && !usesPistol ()) {
|
||||
m_enemyParts &= ~Visibility::Head;
|
||||
}
|
||||
Vector aimPos = m_enemy->v.origin;
|
||||
|
||||
if (m_difficulty > Difficulty::Normal) {
|
||||
aimPos += (m_enemy->v.velocity - pev->velocity) * (getFrameInterval () * 2.0f);
|
||||
Vector spot = m_enemy->v.origin;
|
||||
Vector compensation = 1.0f * m_frameInterval * m_enemy->v.velocity - 1.0f * m_frameInterval * pev->velocity;
|
||||
|
||||
if (!usesSniper () && distance > kDoubleSprayDistance) {
|
||||
compensation *= m_frameInterval;
|
||||
compensation.z = 0.0f;
|
||||
}
|
||||
else {
|
||||
compensation = nullptr;
|
||||
}
|
||||
|
||||
// if we only suspect an enemy behind a wall take the worst skill
|
||||
if (!m_enemyParts && (m_states & Sense::SuspectEnemy)) {
|
||||
aimPos += getBodyOffsetError (distance);
|
||||
spot += getBodyOffsetError (distance);
|
||||
}
|
||||
else if (util.isPlayer (m_enemy)) {
|
||||
const float highOffset = m_kpdRatio < 1.0f ? 1.5f : 0.0f;
|
||||
|
|
@ -522,29 +505,29 @@ const Vector &Bot::getEnemyBodyOffset () {
|
|||
// now check is our skill match to aim at head, else aim at enemy body
|
||||
if (rg.chance (headshotPct)) {
|
||||
if (onLoosingStreak) {
|
||||
aimPos.z = headOffset (m_enemy) + getEnemyBodyOffsetCorrection (distance);
|
||||
spot = m_enemyOrigin + Vector (0.0f, 0.0f, getEnemyBodyOffsetCorrection (distance));
|
||||
}
|
||||
else {
|
||||
aimPos = m_enemy->v.origin + m_enemy->v.view_ofs;
|
||||
spot = m_enemyOrigin;
|
||||
}
|
||||
}
|
||||
else {
|
||||
aimPos.z += highOffset;
|
||||
spot.z += highOffset;
|
||||
}
|
||||
}
|
||||
else if (m_enemyParts & Visibility::Body) {
|
||||
aimPos.z += highOffset;
|
||||
spot = m_enemyOrigin + Vector (0.0f, 0.0f, getEnemyBodyOffsetCorrection (distance));
|
||||
}
|
||||
else if (m_enemyParts & Visibility::Other) {
|
||||
aimPos = m_enemyOrigin;
|
||||
spot = m_enemyOrigin;
|
||||
}
|
||||
else if (m_enemyParts & Visibility::Head) {
|
||||
aimPos.z = headOffset (m_enemy) + getEnemyBodyOffsetCorrection (distance);
|
||||
spot = m_enemyOrigin + Vector (0.0f, 0.0f, getEnemyBodyOffsetCorrection (distance));
|
||||
}
|
||||
}
|
||||
|
||||
m_enemyOrigin = aimPos;
|
||||
m_lastEnemyOrigin = aimPos;
|
||||
m_enemyOrigin = spot + compensation;
|
||||
m_lastEnemyOrigin = spot + compensation;
|
||||
|
||||
// add some error to unskilled bots
|
||||
if (m_difficulty < Difficulty::Hard) {
|
||||
|
|
@ -559,19 +542,19 @@ float Bot::getEnemyBodyOffsetCorrection (float distance) {
|
|||
};
|
||||
|
||||
static float offsetRanges[9][3] = {
|
||||
{ 0.0f, 0.0f, 0.0f }, // none
|
||||
{ 0.0f, 0.0f, 0.0f }, // melee
|
||||
{ 1.5f, 1.5f, -1.2f }, // pistol
|
||||
{ 6.5f, 0.0f, -9.9f }, // shotgun
|
||||
{ 0.5f, -8.5f, -11.0f }, // zoomrifle
|
||||
{ 0.5f, -8.5f, -11.5f }, // rifle
|
||||
{ 2.5f, 0.5f, -4.5f }, // smg
|
||||
{ 0.5f, 0.5f, 1.5f }, // sniper
|
||||
{ 1.5f, -2.0f, -12.0f } // heavy
|
||||
{ 0.0f, 0.0f, 0.0f }, // none
|
||||
{ 0.0f, 0.0f, 4.0f }, // melee
|
||||
{ 3.5f, 2.0f, 1.5f }, // pistol
|
||||
{ 9.5f, 5.0f, -8.0f }, // shotgun
|
||||
{ 4.5f -3.5f, -5.0f }, // zoomrifle
|
||||
{ 5.5f, -3.0f, -5.5f }, // rifle
|
||||
{ 5.5f, -2.5f, -5.5f }, // smg
|
||||
{ 3.5f, 1.5f, -6.0f }, // sniper
|
||||
{ 2.5f, -4.0f, -9.0f } // heavy
|
||||
};
|
||||
|
||||
// only highskilled bots do that
|
||||
if (m_difficulty < Difficulty::Normal) {
|
||||
if (m_difficulty != Difficulty::Expert) {
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
|
|
@ -710,7 +693,7 @@ bool Bot::isPenetrableObstacle2 (const Vector &dest) {
|
|||
}
|
||||
|
||||
if (numHits < 3 && thikness < 98) {
|
||||
if (dest.distanceSq (point) < 13143.0f) {
|
||||
if (dest.distanceSq (point) < cr::square (112.0f)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -774,19 +757,16 @@ bool Bot::needToPauseFiring (float distance) {
|
|||
}
|
||||
float offset = 4.25f;
|
||||
|
||||
if (distance < kSprayDistance / 4) {
|
||||
if (distance < kSprayDistance) {
|
||||
return false;
|
||||
}
|
||||
else if (distance < kSprayDistance) {
|
||||
offset = 10.0f;
|
||||
}
|
||||
else if (distance < kDoubleSprayDistance) {
|
||||
offset = 8.0f;
|
||||
}
|
||||
const float xPunch = cr::deg2rad (pev->punchangle.x);
|
||||
const float yPunch = cr::deg2rad (pev->punchangle.y);
|
||||
|
||||
const float interval = getFrameInterval ();
|
||||
const float interval = m_frameInterval;
|
||||
const float tolerance = (100.0f - static_cast <float> (m_difficulty) * 25.0f) / 99.0f;
|
||||
|
||||
// check if we need to compensate recoil
|
||||
|
|
@ -813,8 +793,7 @@ void Bot::selectWeapons (float distance, int index, int id, int choosen) {
|
|||
|
||||
// select this weapon if it isn't already selected
|
||||
if (m_currentWeapon != id) {
|
||||
const auto &prop = conf.getWeaponProp (id);
|
||||
selectWeaponByName (prop.classname.chars ());
|
||||
selectWeaponById (id);
|
||||
|
||||
// reset burst fire variables
|
||||
m_firePause = 0.0f;
|
||||
|
|
@ -1072,7 +1051,7 @@ void Bot::focusEnemy () {
|
|||
// aim for the head and/or body
|
||||
m_lookAt = getEnemyBodyOffset ();
|
||||
|
||||
if (m_enemySurpriseTime > game.time ()) {
|
||||
if (m_enemySurpriseTime > game.time () && !usesKnife ()) {
|
||||
return;
|
||||
}
|
||||
float distance = m_lookAt.distance2d (getEyesPos ()); // how far away is the enemy scum?
|
||||
|
|
@ -1121,7 +1100,7 @@ void Bot::attackMovement () {
|
|||
return;
|
||||
}
|
||||
|
||||
if (m_lastUsedNodesTime - getFrameInterval () > game.time ()) {
|
||||
if (m_lastUsedNodesTime - m_frameInterval > game.time ()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -1194,17 +1173,29 @@ void Bot::attackMovement () {
|
|||
else {
|
||||
m_fightStyle = Fight::Stay;
|
||||
}
|
||||
|
||||
// do not try to strafe while ducking
|
||||
if (isDucking () || isInNarrowPlace ()) {
|
||||
m_fightStyle = Fight::Stay;
|
||||
}
|
||||
m_lastFightStyleCheck = game.time ();
|
||||
}
|
||||
|
||||
if (m_fightStyle == Fight::Strafe) {
|
||||
if (m_strafeSetTime < game.time ()) {
|
||||
auto swapStrafeCombatDir = [&] () {
|
||||
m_combatStrafeDir = (m_combatStrafeDir == Dodge::Left ? Dodge::Right : Dodge::Left);
|
||||
};
|
||||
|
||||
// to start strafing, we have to first figure out if the target is on the left side or right side
|
||||
auto strafeUpdateTime = [] () {
|
||||
return game.time () + rg.get (0.5f, 1.0f);
|
||||
};
|
||||
|
||||
// to start strafing, we have to first figure out if the target is on the left side or right side
|
||||
if (m_strafeSetTime < game.time ()) {
|
||||
const auto &dirToPoint = (pev->origin - m_enemy->v.origin).normalize2d ();
|
||||
const auto &rightSide = m_enemy->v.v_angle.right ().normalize2d ();
|
||||
|
||||
if ((dirToPoint | rightSide) < 0) {
|
||||
if ((dirToPoint | rightSide) < 0.0f) {
|
||||
m_combatStrafeDir = Dodge::Left;
|
||||
}
|
||||
else {
|
||||
|
|
@ -1212,31 +1203,43 @@ void Bot::attackMovement () {
|
|||
}
|
||||
|
||||
if (rg.chance (30)) {
|
||||
m_combatStrafeDir = (m_combatStrafeDir == Dodge::Left ? Dodge::Right : Dodge::Left);
|
||||
swapStrafeCombatDir ();
|
||||
}
|
||||
m_strafeSetTime = game.time () + rg.get (1.2f, 2.4f);
|
||||
m_strafeSetTime = strafeUpdateTime ();
|
||||
}
|
||||
|
||||
if (m_combatStrafeDir == Dodge::Right) {
|
||||
if (!checkWallOnLeft ()) {
|
||||
m_strafeSpeed = -pev->maxspeed;
|
||||
}
|
||||
else if (!checkWallOnRight ()) {
|
||||
swapStrafeCombatDir ();
|
||||
m_strafeSetTime = strafeUpdateTime ();
|
||||
|
||||
m_strafeSpeed = pev->maxspeed;
|
||||
}
|
||||
else {
|
||||
m_combatStrafeDir = Dodge::Left;
|
||||
m_strafeSetTime = game.time () + rg.get (0.8f, 1.2f);
|
||||
m_strafeSpeed = 0.0f;
|
||||
m_strafeSetTime = strafeUpdateTime ();
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!checkWallOnRight ()) {
|
||||
m_strafeSpeed = pev->maxspeed;
|
||||
}
|
||||
else if (!checkWallOnLeft ()) {
|
||||
swapStrafeCombatDir ();
|
||||
m_strafeSetTime = strafeUpdateTime ();
|
||||
|
||||
m_strafeSpeed = -pev->maxspeed;
|
||||
}
|
||||
else {
|
||||
m_combatStrafeDir = Dodge::Right;
|
||||
m_strafeSetTime = game.time () + rg.get (0.8f, 1.2f);
|
||||
m_strafeSpeed = 0.0f;
|
||||
m_strafeSetTime = strafeUpdateTime ();
|
||||
}
|
||||
}
|
||||
|
||||
if (m_difficulty >= Difficulty::Hard && (m_jumpTime + 5.0f < game.time () && isOnFloor () && rg.get (0, 1000) < (m_isReloading ? 8 : 2) && pev->velocity.length2d () > 150.0f) && !usesSniper ()) {
|
||||
if (m_difficulty >= Difficulty::Normal && (m_jumpTime + 5.0f < game.time () && isOnFloor () && rg.get (0, 1000) < (m_isReloading ? 8 : 2) && pev->velocity.length2d () > 150.0f) && !usesSniper ()) {
|
||||
pev->button |= IN_JUMP;
|
||||
}
|
||||
}
|
||||
|
|
@ -1244,16 +1247,19 @@ void Bot::attackMovement () {
|
|||
if ((m_enemyParts & (Visibility::Head | Visibility::Body)) && getCurrentTaskId () != Task::SeekCover && getCurrentTaskId () != Task::Hunt) {
|
||||
int enemyNearestIndex = graph.getNearest (m_enemy->v.origin);
|
||||
|
||||
if (graph.isDuckVisible (m_currentNodeIndex, enemyNearestIndex) && graph.isDuckVisible (enemyNearestIndex, m_currentNodeIndex)) {
|
||||
m_duckTime = game.time () + 0.64f;
|
||||
if (graph.isVisible (m_currentNodeIndex, enemyNearestIndex) && graph.isDuckVisible (m_currentNodeIndex, enemyNearestIndex) && graph.isDuckVisible (enemyNearestIndex, m_currentNodeIndex)) {
|
||||
m_duckTime = game.time () + m_frameInterval * 2.0f;
|
||||
}
|
||||
}
|
||||
m_moveSpeed = 0.0f;
|
||||
m_strafeSpeed = 0.0f;
|
||||
m_navTimeset = game.time ();
|
||||
}
|
||||
|
||||
if (m_difficulty >= Difficulty::Hard && isOnFloor () && (m_duckTime < game.time ())) {
|
||||
m_navTimeset = game.time ();
|
||||
m_moveToGoal = false;
|
||||
m_checkTerrain = false;
|
||||
|
||||
if (m_difficulty >= Difficulty::Normal && isOnFloor () && m_duckTime < game.time ()) {
|
||||
if (distance < 768.0f) {
|
||||
if (rg.get (0, 1000) < rg.get (7, 12) && pev->velocity.length2d () > 150.0f && isInViewCone (m_enemy->v.origin)) {
|
||||
pev->button |= IN_JUMP;
|
||||
|
|
@ -1261,13 +1267,18 @@ void Bot::attackMovement () {
|
|||
}
|
||||
}
|
||||
|
||||
if (m_isReloading) {
|
||||
m_moveSpeed = -pev->maxspeed;
|
||||
m_duckTime = game.time () - 1.0f;
|
||||
}
|
||||
|
||||
if (!isInWater () && !isOnLadder () && (m_moveSpeed > 0.0f || m_strafeSpeed >= 0.0f)) {
|
||||
Vector right, forward;
|
||||
pev->v_angle.angleVectors (&forward, &right, nullptr);
|
||||
|
||||
const auto &front = right * m_moveSpeed * 0.2f;
|
||||
const auto &side = right * m_strafeSpeed * 0.2f;
|
||||
const auto &spot = pev->origin + front + side + pev->velocity * getFrameInterval ();
|
||||
const auto &spot = pev->origin + front + side + pev->velocity * m_frameInterval;
|
||||
|
||||
if (isDeadlyMove (spot)) {
|
||||
m_strafeSpeed = -m_strafeSpeed;
|
||||
|
|
@ -1461,9 +1472,9 @@ void Bot::selectBestWeapon () {
|
|||
// this function chooses best weapon, from weapons that bot currently own, and change
|
||||
// current weapon to best one.
|
||||
|
||||
// if knife mode activated, force bot to use knife
|
||||
if (cv_jasonmode.bool_ ()) {
|
||||
// if knife mode activated, force bot to use knife
|
||||
selectWeaponByName ("weapon_knife");
|
||||
selectWeaponById (Weapon::Knife);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -1505,11 +1516,11 @@ void Bot::selectBestWeapon () {
|
|||
chosenWeaponIndex %= kNumWeapons + 1;
|
||||
selectIndex = chosenWeaponIndex;
|
||||
|
||||
int id = tab[selectIndex].id;
|
||||
const int id = tab[selectIndex].id;
|
||||
|
||||
// select this weapon if it isn't already selected
|
||||
if (m_currentWeapon != id) {
|
||||
selectWeaponByName (tab[selectIndex].name);
|
||||
selectWeaponById (tab[selectIndex].id);
|
||||
}
|
||||
m_isReloading = false;
|
||||
m_reloadState = Reload::None;
|
||||
|
|
@ -1543,15 +1554,6 @@ int Bot::bestWeaponCarried () {
|
|||
return num;
|
||||
}
|
||||
|
||||
void Bot::selectWeaponByName (StringRef name) {
|
||||
issueCommand (name.chars ());
|
||||
}
|
||||
|
||||
void Bot::selectWeaponByIndex (int index) {
|
||||
auto tab = conf.getRawWeapons ();
|
||||
issueCommand (tab[index].name);
|
||||
}
|
||||
|
||||
void Bot::decideFollowUser () {
|
||||
// this function forces bot to follow user
|
||||
Array <edict_t *> users;
|
||||
|
|
@ -1685,7 +1687,7 @@ void Bot::checkReload () {
|
|||
|
||||
if (isLowOnAmmo (prop.id, 0.75f) && getAmmo (prop.id) > 0) {
|
||||
if (m_currentWeapon != prop.id) {
|
||||
selectWeaponByName (prop.classname);
|
||||
selectWeaponById (prop.id);
|
||||
}
|
||||
pev->button &= ~IN_ATTACK;
|
||||
|
||||
|
|
@ -1719,3 +1721,311 @@ float Bot::calculateScaleFactor (edict_t *ent) {
|
|||
|
||||
return entArea / botArea;
|
||||
}
|
||||
|
||||
Vector Bot::calcToss (const Vector &start, const Vector &stop) {
|
||||
// this function returns the velocity at which an object should looped from start to land near end.
|
||||
// returns null vector if toss is not feasible.
|
||||
|
||||
TraceResult tr {};
|
||||
float gravity = sv_gravity.float_ () * 0.55f;
|
||||
|
||||
Vector end = stop - pev->velocity;
|
||||
end.z -= 15.0f;
|
||||
|
||||
if (cr::abs (end.z - start.z) > 500.0f) {
|
||||
return nullptr;
|
||||
}
|
||||
Vector midPoint = start + (end - start) * 0.5f;
|
||||
game.testHull (midPoint, midPoint + Vector (0.0f, 0.0f, 500.0f), TraceIgnore::Monsters, head_hull, ent (), &tr);
|
||||
|
||||
if (tr.flFraction < 1.0f && tr.pHit) {
|
||||
midPoint = tr.vecEndPos;
|
||||
midPoint.z = tr.pHit->v.absmin.z - 1.0f;
|
||||
}
|
||||
|
||||
if (midPoint.z < start.z || midPoint.z < end.z) {
|
||||
return nullptr;
|
||||
}
|
||||
float timeOne = cr::sqrtf ((midPoint.z - start.z) / (0.5f * gravity));
|
||||
float timeTwo = cr::sqrtf ((midPoint.z - end.z) / (0.5f * gravity));
|
||||
|
||||
if (timeOne < 0.1f) {
|
||||
return nullptr;
|
||||
}
|
||||
Vector velocity = (end - start) / (timeOne + timeTwo);
|
||||
velocity.z = gravity * timeOne;
|
||||
|
||||
Vector apex = start + velocity * timeOne;
|
||||
apex.z = midPoint.z;
|
||||
|
||||
game.testHull (start, apex, TraceIgnore::None, head_hull, ent (), &tr);
|
||||
|
||||
if (tr.flFraction < 1.0f || tr.fAllSolid) {
|
||||
return nullptr;
|
||||
}
|
||||
game.testHull (end, apex, TraceIgnore::Monsters, head_hull, ent (), &tr);
|
||||
|
||||
if (!cr::fequal (tr.flFraction, 1.0f)) {
|
||||
float dot = -(tr.vecPlaneNormal | (apex - end).normalize ());
|
||||
|
||||
if (dot > 0.75f || tr.flFraction < 0.8f) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
return velocity * 0.777f;
|
||||
}
|
||||
|
||||
Vector Bot::calcThrow (const Vector &start, const Vector &stop) {
|
||||
// this function returns the velocity vector at which an object should be thrown from start to hit end.
|
||||
// returns null vector if throw is not feasible.
|
||||
|
||||
Vector velocity = stop - start;
|
||||
TraceResult tr {};
|
||||
|
||||
float gravity = sv_gravity.float_ () * 0.55f;
|
||||
float time = velocity.length () / 195.0f;
|
||||
|
||||
if (time < 0.01f) {
|
||||
return nullptr;
|
||||
}
|
||||
else if (time > 2.0f) {
|
||||
time = 1.2f;
|
||||
}
|
||||
const float half = time * 0.5f;
|
||||
|
||||
velocity = velocity * (1.0f / time);
|
||||
velocity.z += gravity * half * half;
|
||||
|
||||
Vector apex = start + (stop - start) * 0.5f;
|
||||
apex.z += 0.5f * gravity * half;
|
||||
|
||||
game.testHull (start, apex, TraceIgnore::None, head_hull, ent (), &tr);
|
||||
|
||||
if (!cr::fequal (tr.flFraction, 1.0f)) {
|
||||
return nullptr;
|
||||
}
|
||||
game.testHull (stop, apex, TraceIgnore::Monsters, head_hull, ent (), &tr);
|
||||
|
||||
if (!cr::fequal (tr.flFraction, 1.0) || tr.fAllSolid) {
|
||||
float dot = -(tr.vecPlaneNormal | (apex - stop).normalize ());
|
||||
|
||||
if (dot > 0.75f || tr.flFraction < 0.8f) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
return velocity * 0.7793f;
|
||||
}
|
||||
|
||||
edict_t *Bot::setCorrectGrenadeVelocity (const char *model) {
|
||||
edict_t *result = nullptr;
|
||||
|
||||
game.searchEntities ("classname", "grenade", [&] (edict_t *ent) {
|
||||
if (ent->v.owner == this->ent () && util.isModel (ent, model)) {
|
||||
result = ent;
|
||||
|
||||
// set the correct velocity for the grenade
|
||||
if (m_grenade.lengthSq () > 100.0f) {
|
||||
ent->v.velocity = m_grenade + (m_grenade * m_frameInterval * 4.0f);
|
||||
}
|
||||
m_grenadeCheckTime = game.time () + 3.0f;
|
||||
|
||||
selectBestWeapon ();
|
||||
completeTask ();
|
||||
|
||||
return EntitySearchResult::Break;
|
||||
}
|
||||
return EntitySearchResult::Continue;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
void Bot::checkGrenadesThrow () {
|
||||
|
||||
// do not check cancel if we have grenade in out hands
|
||||
bool preventibleTasks = getCurrentTaskId () == Task::PlantBomb || getCurrentTaskId () == Task::DefuseBomb;
|
||||
|
||||
auto clearThrowStates = [] (uint32_t &states) {
|
||||
states &= ~(Sense::ThrowExplosive | Sense::ThrowFlashbang | Sense::ThrowSmoke);
|
||||
};
|
||||
|
||||
// check if throwing a grenade is a good thing to do...
|
||||
if (preventibleTasks || isInNarrowPlace () || cv_ignore_enemies.bool_ () || m_isUsingGrenade || m_grenadeRequested || m_isReloading || cv_jasonmode.bool_ () || (m_grenadeRequested || m_grenadeCheckTime >= game.time ())) {
|
||||
clearThrowStates (m_states);
|
||||
return;
|
||||
}
|
||||
|
||||
// check again in some seconds
|
||||
m_grenadeCheckTime = game.time () + kGrenadeCheckTime;
|
||||
|
||||
if (!util.isAlive (m_lastEnemy) || !(m_states & (Sense::SuspectEnemy | Sense::HearingEnemy))) {
|
||||
clearThrowStates (m_states);
|
||||
return;
|
||||
}
|
||||
|
||||
// check if we have grenades to throw
|
||||
int grenadeToThrow = bestGrenadeCarried ();
|
||||
|
||||
// if we don't have grenades no need to check it this round again
|
||||
if (grenadeToThrow == -1) {
|
||||
m_grenadeCheckTime = game.time () + 15.0f; // changed since, conzero can drop grens from dead players
|
||||
|
||||
clearThrowStates (m_states);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
int cancelProb = 20;
|
||||
|
||||
if (grenadeToThrow == Weapon::Flashbang) {
|
||||
cancelProb = 25;
|
||||
}
|
||||
else if (grenadeToThrow == Weapon::Smoke) {
|
||||
cancelProb = 35;
|
||||
}
|
||||
if (rg.chance (cancelProb)) {
|
||||
clearThrowStates (m_states);
|
||||
return;
|
||||
}
|
||||
}
|
||||
float distance = m_lastEnemyOrigin.distance2d (pev->origin);
|
||||
|
||||
// don't throw grenades at anything that isn't on the ground!
|
||||
if (!(m_lastEnemy->v.flags & FL_ONGROUND) && !m_lastEnemy->v.waterlevel && m_lastEnemyOrigin.z > pev->absmax.z) {
|
||||
distance = kInfiniteDistance;
|
||||
}
|
||||
|
||||
// too high to throw?
|
||||
if (m_lastEnemy->v.origin.z > pev->origin.z + 500.0f) {
|
||||
distance = kInfiniteDistance;
|
||||
}
|
||||
|
||||
// enemy within a good throw distance?
|
||||
if (!m_lastEnemyOrigin.empty () && distance > (grenadeToThrow == Weapon::Smoke ? 200.0f : 400.0f) && distance < 1200.0f) {
|
||||
bool allowThrowing = true;
|
||||
|
||||
// care about different grenades
|
||||
switch (grenadeToThrow) {
|
||||
case Weapon::Explosive:
|
||||
if (numFriendsNear (m_lastEnemy->v.origin, 256.0f) > 0) {
|
||||
allowThrowing = false;
|
||||
}
|
||||
else {
|
||||
float radius = m_lastEnemy->v.velocity.length2d ();
|
||||
const Vector &pos = (m_lastEnemy->v.velocity * 0.5f).get2d () + m_lastEnemy->v.origin;
|
||||
|
||||
if (radius < 164.0f) {
|
||||
radius = 164.0f;
|
||||
}
|
||||
auto predicted = graph.searchRadius (radius, pos, 12);
|
||||
|
||||
if (predicted.empty ()) {
|
||||
m_states &= ~Sense::ThrowExplosive;
|
||||
break;
|
||||
}
|
||||
|
||||
for (const auto predict : predicted) {
|
||||
allowThrowing = true;
|
||||
|
||||
if (!graph.exists (predict)) {
|
||||
allowThrowing = false;
|
||||
continue;
|
||||
}
|
||||
m_throw = graph[predict].origin;
|
||||
|
||||
auto throwPos = calcThrow (getEyesPos (), m_throw);
|
||||
|
||||
if (throwPos.lengthSq () < 100.0f) {
|
||||
throwPos = calcToss (getEyesPos (), m_throw);
|
||||
}
|
||||
|
||||
if (throwPos.empty ()) {
|
||||
allowThrowing = false;
|
||||
}
|
||||
else {
|
||||
m_throw.z += 110.0f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (allowThrowing) {
|
||||
m_states |= Sense::ThrowExplosive;
|
||||
}
|
||||
else {
|
||||
m_states &= ~Sense::ThrowExplosive;
|
||||
}
|
||||
break;
|
||||
|
||||
case Weapon::Flashbang:
|
||||
{
|
||||
int nearest = graph.getNearest ((m_lastEnemy->v.velocity * 0.5f).get2d () + m_lastEnemy->v.origin);
|
||||
|
||||
if (nearest != kInvalidNodeIndex) {
|
||||
m_throw = graph[nearest].origin;
|
||||
|
||||
if (numFriendsNear (m_throw, 256.0f) > 0) {
|
||||
allowThrowing = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
allowThrowing = false;
|
||||
}
|
||||
|
||||
if (allowThrowing) {
|
||||
auto throwPos = calcThrow (getEyesPos (), m_throw);
|
||||
|
||||
if (throwPos.lengthSq () < 100.0f) {
|
||||
throwPos = calcToss (getEyesPos (), m_throw);
|
||||
}
|
||||
|
||||
if (throwPos.empty ()) {
|
||||
allowThrowing = false;
|
||||
}
|
||||
else {
|
||||
m_throw.z += 110.0f;
|
||||
}
|
||||
}
|
||||
|
||||
if (allowThrowing) {
|
||||
m_states |= Sense::ThrowFlashbang;
|
||||
}
|
||||
else {
|
||||
m_states &= ~Sense::ThrowFlashbang;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case Weapon::Smoke:
|
||||
if (allowThrowing && !game.isNullEntity (m_lastEnemy)) {
|
||||
if (util.getShootingCone (m_lastEnemy, pev->origin) >= 0.9f) {
|
||||
allowThrowing = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (allowThrowing) {
|
||||
m_states |= Sense::ThrowSmoke;
|
||||
}
|
||||
else {
|
||||
m_states &= ~Sense::ThrowSmoke;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
clearThrowStates (m_states);
|
||||
return;
|
||||
}
|
||||
const float kMaxThrowTime = game.time () + kGrenadeCheckTime * 6.0f;
|
||||
|
||||
if (m_states & Sense::ThrowExplosive) {
|
||||
startTask (Task::ThrowExplosive, TaskPri::Throw, kInvalidNodeIndex, kMaxThrowTime, false);
|
||||
}
|
||||
else if (m_states & Sense::ThrowFlashbang) {
|
||||
startTask (Task::ThrowFlashbang, TaskPri::Throw, kInvalidNodeIndex, kMaxThrowTime, false);
|
||||
}
|
||||
else if (m_states & Sense::ThrowSmoke) {
|
||||
startTask (Task::ThrowSmoke, TaskPri::Throw, kInvalidNodeIndex, kMaxThrowTime, false);
|
||||
}
|
||||
}
|
||||
else {
|
||||
clearThrowStates (m_states);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -158,7 +158,7 @@ void BotConfig::loadWeaponsConfig () {
|
|||
}
|
||||
};
|
||||
|
||||
auto addIntEntries = [] (SmallArray <int32> &to, StringRef name, const StringArray &data) {
|
||||
auto addIntEntries = [] (SmallArray <int32_t> &to, StringRef name, const StringArray &data) {
|
||||
if (data.length () != to.length ()) {
|
||||
logger.error ("%s entry in weapons config is not valid or malformed (%d/%d).", name, data.length (), to.length ());
|
||||
return;
|
||||
|
|
@ -334,9 +334,9 @@ void BotConfig::loadChatterConfig () {
|
|||
for (const auto &event : chatterEventMap) {
|
||||
if (event.str == items[0]) {
|
||||
// this does common work of parsing comma-separated chatter line
|
||||
auto sounds = items[1].split (",");
|
||||
auto sentences = items[1].split (",");
|
||||
|
||||
for (auto &sound : sounds) {
|
||||
for (auto &sound : sentences) {
|
||||
sound.trim ().trim ("\"");
|
||||
auto duration = game.getWaveLen (sound.chars ());
|
||||
|
||||
|
|
@ -344,7 +344,7 @@ void BotConfig::loadChatterConfig () {
|
|||
m_chatter[event.code].emplace (cr::move (sound), event.repeat, duration);
|
||||
}
|
||||
}
|
||||
sounds.clear ();
|
||||
sentences.clear ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -553,10 +553,10 @@ void BotConfig::loadDifficultyConfig () {
|
|||
};
|
||||
|
||||
// currently, mindelay, maxdelay, headprob, seenthruprob, heardthruprob
|
||||
constexpr uint32 kMaxDifficultyValues = 5;
|
||||
constexpr uint32_t kMaxDifficultyValues = 5;
|
||||
|
||||
// helper for parsing each level
|
||||
auto parseLevel = [&] (int32 level, StringRef data) {
|
||||
auto parseLevel = [&] (int32_t level, StringRef data) {
|
||||
auto values = data.split <String> (",");
|
||||
|
||||
if (values.length () != kMaxDifficultyValues) {
|
||||
|
|
@ -796,14 +796,14 @@ const char *BotConfig::translate (StringRef input) {
|
|||
}
|
||||
|
||||
void BotConfig::showCustomValues () {
|
||||
game.print ("Current values for custom config items:");
|
||||
ctrl.msg ("Current values for custom config items:");
|
||||
|
||||
m_custom.foreach ([&] (const String &key, const String &val) {
|
||||
game.print (" %s = %s", key, val);
|
||||
ctrl.msg (" %s = %s", key, val);
|
||||
});
|
||||
}
|
||||
|
||||
uint32 BotConfig::hashLangString (StringRef str) {
|
||||
uint32_t BotConfig::hashLangString (StringRef str) {
|
||||
auto test = [] (const char ch) {
|
||||
return (ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z');
|
||||
};
|
||||
|
|
|
|||
|
|
@ -24,15 +24,15 @@ int BotControl::cmdAddBot () {
|
|||
m_args.resize (max);
|
||||
|
||||
// if team is specified, modify args to set team
|
||||
if (strValue (alias).find ("_ct", 0) != String::InvalidIndex) {
|
||||
if (strValue (alias).endsWith ("_ct")) {
|
||||
m_args.set (team, "2");
|
||||
}
|
||||
else if (strValue (alias).find ("_t", 0) != String::InvalidIndex) {
|
||||
else if (strValue (alias).endsWith ("_t")) {
|
||||
m_args.set (team, "1");
|
||||
}
|
||||
|
||||
// if highskilled bot is requsted set personality to rusher and maxout difficulty
|
||||
if (strValue (alias).find ("hs", 0) != String::InvalidIndex) {
|
||||
if (strValue (alias).endsWith ("_hs")) {
|
||||
m_args.set (difficulty, "4");
|
||||
m_args.set (personality, "1");
|
||||
}
|
||||
|
|
@ -676,13 +676,13 @@ int BotControl::cmdNodePathCreate () {
|
|||
graph.setEditFlag (GraphEdit::On);
|
||||
|
||||
// choose the direction for path creation
|
||||
if (strValue (cmd).find ("_both", 0) != String::InvalidIndex) {
|
||||
if (strValue (cmd).endsWith ("_both")) {
|
||||
graph.pathCreate (PathConnection::Bidirectional);
|
||||
}
|
||||
else if (strValue (cmd).find ("_in", 0) != String::InvalidIndex) {
|
||||
else if (strValue (cmd).endsWith ("_in")) {
|
||||
graph.pathCreate (PathConnection::Incoming);
|
||||
}
|
||||
else if (strValue (cmd).find ("_out", 0) != String::InvalidIndex) {
|
||||
else if (strValue (cmd).endsWith ("_out")) {
|
||||
graph.pathCreate (PathConnection::Outgoing);
|
||||
}
|
||||
else {
|
||||
|
|
@ -1852,7 +1852,7 @@ void BotControl::showMenu (int id) {
|
|||
}
|
||||
auto &client = util.getClient (game.indexOfPlayer (m_ent));
|
||||
|
||||
auto sendMenu = [&] (int32 slots, bool last, StringRef text) {
|
||||
auto sendMenu = [&] (int32_t slots, bool last, StringRef text) {
|
||||
MessageWriter (MSG_ONE, msgs.id (NetMsg::ShowMenu), nullptr, m_ent)
|
||||
.writeShort (slots)
|
||||
.writeChar (-1)
|
||||
|
|
@ -1943,7 +1943,7 @@ void BotControl::kickBotByMenu (int page) {
|
|||
|
||||
for (auto &menu : m_menus) {
|
||||
if (menu.ident == id) {
|
||||
menu.slots = static_cast <int> (static_cast <uint32> (menuKeys) & static_cast <uint32> (-1));
|
||||
menu.slots = static_cast <int> (static_cast <uint32_t> (menuKeys) & static_cast <uint32_t> (-1));
|
||||
menu.text = menus;
|
||||
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -423,7 +423,7 @@ void Game::setPlayerStartDrawModels () {
|
|||
});
|
||||
}
|
||||
|
||||
bool Game::checkVisibility (edict_t *ent, uint8 *set) {
|
||||
bool Game::checkVisibility (edict_t *ent, uint8_t *set) {
|
||||
if (!set) {
|
||||
return true;
|
||||
}
|
||||
|
|
@ -452,13 +452,13 @@ bool Game::checkVisibility (edict_t *ent, uint8 *set) {
|
|||
return engfuncs.pfnCheckVisibility (ent, set) > 0;
|
||||
}
|
||||
|
||||
uint8 *Game::getVisibilitySet (Bot *bot, bool pvs) {
|
||||
uint8_t *Game::getVisibilitySet (Bot *bot, bool pvs) {
|
||||
if (is (GameFlags::Xash3D)) {
|
||||
return nullptr;
|
||||
}
|
||||
auto eyes = bot->getEyesPos ();
|
||||
|
||||
if (bot->pev->flags & FL_DUCKING) {
|
||||
if (bot->isDucking ()) {
|
||||
eyes += VEC_HULL_MIN - VEC_DUCK_HULL_MIN;
|
||||
}
|
||||
float org[3] { eyes.x, eyes.y, eyes.z };
|
||||
|
|
@ -609,7 +609,7 @@ bool Game::isSoftwareRenderer () {
|
|||
return false;
|
||||
}
|
||||
|
||||
void Game::addNewCvar (const char *name, const char *value, const char *info, bool bounded, float min, float max, int32 varType, bool missingAction, const char *regval, ConVar *self) {
|
||||
void Game::addNewCvar (const char *name, const char *value, const char *info, bool bounded, float min, float max, int32_t varType, bool missingAction, const char *regval, ConVar *self) {
|
||||
// this function adds globally defined variable to registration stack
|
||||
|
||||
ConVarReg reg {};
|
||||
|
|
@ -1112,7 +1112,7 @@ void LightMeasure::animateLight () {
|
|||
m_lightstyleValue[j] = 256;
|
||||
continue;
|
||||
}
|
||||
m_lightstyleValue[j] = static_cast <uint32> (m_lightstyle[j].map[index % m_lightstyle[j].length] - 'a') * 22u;
|
||||
m_lightstyleValue[j] = static_cast <uint32_t> (m_lightstyle[j].map[index % m_lightstyle[j].length] - 'a') * 22u;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1214,7 +1214,7 @@ template <typename S, typename M> bool LightMeasure::recursiveLightPoint (const
|
|||
|
||||
// compute the lightmap color at a particular point
|
||||
for (int maps = 0u; maps < MAXLIGHTMAPS && surf->styles[maps] != 255u; ++maps) {
|
||||
uint32 scale = m_lightstyleValue[surf->styles[maps]];
|
||||
uint32_t scale = m_lightstyleValue[surf->styles[maps]];
|
||||
|
||||
m_point.red += lightmap->r * scale;
|
||||
m_point.green += lightmap->g * scale;
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
#include <yapb.h>
|
||||
|
||||
// on other tran win32/linux platforms i.e. arm we're using xash3d engine to run which exposes
|
||||
// on other than win32/linux platforms i.e. arm we're using xash3d engine to run which exposes
|
||||
// nice interface to handle with linkents. if ever rehlds or hlds engine will ever run on ARM or
|
||||
// other platforms, and you wan't to run bot on it without metamod, consider enabling LINKENT_STATIC_THUNKS
|
||||
// when compiling the bot, to get it supported.
|
||||
|
|
|
|||
|
|
@ -417,7 +417,7 @@ void BotGraph::addPath (int addIndex, int pathIndex, float distance) {
|
|||
// check for free space in the connection indices
|
||||
for (auto &link : path.links) {
|
||||
if (link.index == kInvalidNodeIndex) {
|
||||
link.index = static_cast <int16> (pathIndex);
|
||||
link.index = static_cast <int16_t> (pathIndex);
|
||||
link.distance = cr::abs (static_cast <int> (distance));
|
||||
|
||||
ctrl.msg ("Path added from %d to %d.", addIndex, pathIndex);
|
||||
|
|
@ -439,7 +439,7 @@ void BotGraph::addPath (int addIndex, int pathIndex, float distance) {
|
|||
if (slot != kInvalidNodeIndex) {
|
||||
ctrl.msg ("Path added from %d to %d.", addIndex, pathIndex);
|
||||
|
||||
path.links[slot].index = static_cast <int16> (pathIndex);
|
||||
path.links[slot].index = static_cast <int16_t> (pathIndex);
|
||||
path.links[slot].distance = cr::abs (static_cast <int> (distance));
|
||||
}
|
||||
}
|
||||
|
|
@ -524,7 +524,7 @@ IntArray BotGraph::searchRadius (float radius, const Vector &origin, int maxCoun
|
|||
// returns all nodes within radius from position
|
||||
|
||||
IntArray result;
|
||||
auto &bucket = getNodesInBucket (origin);
|
||||
const auto &bucket = getNodesInBucket (origin);
|
||||
|
||||
if (bucket.empty ()) {
|
||||
result.push (getNearestNoBuckets (origin, radius));
|
||||
|
|
@ -928,7 +928,7 @@ bool BotGraph::isConnected (int a, int b) {
|
|||
int BotGraph::getFacingIndex () {
|
||||
// find the waypoint the user is pointing at
|
||||
|
||||
Twin <int32, float> result { kInvalidNodeIndex, 5.32f };
|
||||
Twin <int32_t, float> result { kInvalidNodeIndex, 5.32f };
|
||||
auto nearestNode = getEditorNearest ();
|
||||
|
||||
// check bounds from eyes of editor
|
||||
|
|
@ -1171,7 +1171,7 @@ void BotGraph::calculatePathRadius (int index) {
|
|||
TraceResult tr {};
|
||||
bool wayBlocked = false;
|
||||
|
||||
for (int32 scanDistance = 32; scanDistance < 128; scanDistance += 16) {
|
||||
for (int32_t scanDistance = 32; scanDistance < 128; scanDistance += 16) {
|
||||
auto scan = static_cast <float> (scanDistance);
|
||||
start = path.origin;
|
||||
|
||||
|
|
@ -1180,7 +1180,7 @@ void BotGraph::calculatePathRadius (int index) {
|
|||
|
||||
path.radius = scan;
|
||||
|
||||
for (int32 circleRadius = 0; circleRadius < 360; circleRadius += 20) {
|
||||
for (int32_t circleRadius = 0; circleRadius < 360; circleRadius += 20) {
|
||||
const auto &forward = direction.forward ();
|
||||
|
||||
auto radiusStart = start + forward * scan;
|
||||
|
|
@ -1305,7 +1305,7 @@ void BotGraph::loadVisibility () {
|
|||
if (m_paths.empty ()) {
|
||||
return;
|
||||
}
|
||||
bool dataLoaded = loadStorage <uint8> ("vis", "Visibility", StorageOption::Vistable, StorageVersion::Vistable, m_vistable, nullptr, nullptr);
|
||||
bool dataLoaded = loadStorage <uint8_t> ("vis", "Visibility", StorageOption::Vistable, StorageVersion::Vistable, m_vistable, nullptr, nullptr);
|
||||
|
||||
// if loaded, do not recalculate visibility
|
||||
if (dataLoaded) {
|
||||
|
|
@ -1317,7 +1317,7 @@ void BotGraph::saveVisibility () {
|
|||
if (m_paths.empty () || m_hasChanged || m_needsVisRebuild) {
|
||||
return;
|
||||
}
|
||||
saveStorage <uint8> ("vis", "Visibility", StorageOption::Vistable, StorageVersion::Vistable, m_vistable, nullptr);
|
||||
saveStorage <uint8_t> ("vis", "Visibility", StorageOption::Vistable, StorageVersion::Vistable, m_vistable, nullptr);
|
||||
}
|
||||
|
||||
bool BotGraph::loadPathMatrix () {
|
||||
|
|
@ -1345,8 +1345,8 @@ bool BotGraph::loadPathMatrix () {
|
|||
if (!exists (link.index)) {
|
||||
continue;
|
||||
}
|
||||
(matrix + (i * count) + link.index)->dist = static_cast <int16> (link.distance);
|
||||
(matrix + (i * count) + link.index)->index = static_cast <int16> (link.index);
|
||||
(matrix + (i * count) + link.index)->dist = static_cast <int16_t> (link.distance);
|
||||
(matrix + (i * count) + link.index)->index = static_cast <int16_t> (link.index);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1360,7 +1360,7 @@ bool BotGraph::loadPathMatrix () {
|
|||
int distance = (matrix + (i * count) + k)->dist + (matrix + (k * count) + j)->dist;
|
||||
|
||||
if (distance < (matrix + (i * count) + j)->dist) {
|
||||
(matrix + (i * count) + j)->dist = static_cast <int16> (distance);
|
||||
(matrix + (i * count) + j)->dist = static_cast <int16_t> (distance);
|
||||
(matrix + (i * count) + j)->index = (matrix + (i * count) + k)->index;
|
||||
}
|
||||
}
|
||||
|
|
@ -1404,7 +1404,7 @@ void BotGraph::initNarrowPlaces () {
|
|||
if (m_paths.empty () || m_narrowChecked) {
|
||||
return;
|
||||
}
|
||||
constexpr int32 kNarrowPlacesMinGraphVersion = 2;
|
||||
constexpr int32_t kNarrowPlacesMinGraphVersion = 2;
|
||||
|
||||
// if version 2 or higher, narrow places already initialized and saved into file
|
||||
if (m_graphHeader.version >= kNarrowPlacesMinGraphVersion) {
|
||||
|
|
@ -1463,6 +1463,7 @@ void BotGraph::initNarrowPlaces () {
|
|||
return false;
|
||||
};
|
||||
|
||||
|
||||
if (directionCheck (-forward * distance)) {
|
||||
accumWeight += 1;
|
||||
}
|
||||
|
|
@ -1625,10 +1626,10 @@ template <typename U> bool BotGraph::saveStorage (StringRef ext, StringRef name,
|
|||
return false;
|
||||
}
|
||||
auto rawLength = data.length () * sizeof (U);
|
||||
SmallArray <uint8> compressed (rawLength + sizeof (uint8) * ULZ::Excess);
|
||||
SmallArray <uint8_t> compressed (rawLength + sizeof (uint8_t) * ULZ::Excess);
|
||||
|
||||
// try to compress
|
||||
auto compressedLength = static_cast <size_t> (ulz.compress (reinterpret_cast <uint8 *> (data.data ()), static_cast <int32> (rawLength), reinterpret_cast <uint8 *> (compressed.data ())));
|
||||
auto compressedLength = static_cast <size_t> (ulz.compress (reinterpret_cast <uint8_t *> (data.data ()), static_cast <int32_t> (rawLength), reinterpret_cast <uint8_t *> (compressed.data ())));
|
||||
|
||||
if (compressedLength > 0) {
|
||||
StorageHeader hdr {};
|
||||
|
|
@ -1637,11 +1638,11 @@ template <typename U> bool BotGraph::saveStorage (StringRef ext, StringRef name,
|
|||
hdr.version = version;
|
||||
hdr.options = options;
|
||||
hdr.length = length ();
|
||||
hdr.compressed = static_cast <int32> (compressedLength);
|
||||
hdr.uncompressed = static_cast <int32> (rawLength);
|
||||
hdr.compressed = static_cast <int32_t> (compressedLength);
|
||||
hdr.uncompressed = static_cast <int32_t> (rawLength);
|
||||
|
||||
file.write (&hdr, sizeof (StorageHeader));
|
||||
file.write (compressed.data (), sizeof (uint8), compressedLength);
|
||||
file.write (compressed.data (), sizeof (uint8_t), compressedLength);
|
||||
|
||||
// add extension
|
||||
if ((options & StorageOption::Exten) && exten != nullptr) {
|
||||
|
|
@ -1656,7 +1657,7 @@ template <typename U> bool BotGraph::saveStorage (StringRef ext, StringRef name,
|
|||
return true;
|
||||
}
|
||||
|
||||
template <typename U> bool BotGraph::loadStorage (StringRef ext, StringRef name, StorageOption options, StorageVersion version, SmallArray <U> &data, ExtenHeader *exten, int32 *outOptions) {
|
||||
template <typename U> bool BotGraph::loadStorage (StringRef ext, StringRef name, StorageOption options, StorageVersion version, SmallArray <U> &data, ExtenHeader *exten, int32_t *outOptions) {
|
||||
String filename;
|
||||
filename.assignf ("%s.%s", game.getMapName (), ext).lowercase ();
|
||||
|
||||
|
|
@ -1790,7 +1791,7 @@ template <typename U> bool BotGraph::loadStorage (StringRef ext, StringRef name,
|
|||
auto compressedSize = static_cast <size_t> (hdr.compressed);
|
||||
auto numberNodes = static_cast <size_t> (hdr.length);
|
||||
|
||||
SmallArray <uint8> compressed (compressedSize + sizeof (uint8) * ULZ::Excess);
|
||||
SmallArray <uint8_t> compressed (compressedSize + sizeof (uint8_t) * ULZ::Excess);
|
||||
|
||||
// graph is not resized upon load
|
||||
if (isGraph) {
|
||||
|
|
@ -1798,10 +1799,10 @@ template <typename U> bool BotGraph::loadStorage (StringRef ext, StringRef name,
|
|||
}
|
||||
|
||||
// read compressed data
|
||||
if (file.read (compressed.data (), sizeof (uint8), compressedSize) == compressedSize) {
|
||||
if (file.read (compressed.data (), sizeof (uint8_t), compressedSize) == compressedSize) {
|
||||
|
||||
// try to uncompress
|
||||
if (ulz.uncompress (compressed.data (), hdr.compressed, reinterpret_cast <uint8 *> (data.data ()), hdr.uncompressed) == ULZ::UncompressFailure) {
|
||||
if (ulz.uncompress (compressed.data (), hdr.compressed, reinterpret_cast <uint8_t *> (data.data ()), hdr.uncompressed) == ULZ::UncompressFailure) {
|
||||
return raiseLoadingError (isGraph, file, "Unable to decompress ULZ data for %s (filename: '%s').", name, filename);
|
||||
}
|
||||
else {
|
||||
|
|
@ -1844,7 +1845,7 @@ template <typename U> bool BotGraph::loadStorage (StringRef ext, StringRef name,
|
|||
|
||||
bool BotGraph::loadGraphData () {
|
||||
ExtenHeader exten {};
|
||||
int32 outOptions = 0;
|
||||
int32_t outOptions = 0;
|
||||
|
||||
m_graphHeader = {};
|
||||
m_extenHeader = {};
|
||||
|
|
@ -2079,7 +2080,7 @@ void BotGraph::rebuildVisibility () {
|
|||
}
|
||||
|
||||
TraceResult tr {};
|
||||
uint8 res, shift;
|
||||
uint8_t res, shift;
|
||||
|
||||
for (const auto &vis : m_paths) {
|
||||
Vector sourceDuck = vis.origin;
|
||||
|
|
@ -2093,7 +2094,7 @@ void BotGraph::rebuildVisibility () {
|
|||
sourceDuck.z += -18.0f + 12.0f;
|
||||
sourceStand.z += 28.0f;
|
||||
}
|
||||
uint16 standCount = 0, crouchCount = 0;
|
||||
uint16_t standCount = 0, crouchCount = 0;
|
||||
|
||||
for (const auto &path : m_paths) {
|
||||
// first check ducked visibility
|
||||
|
|
@ -2146,9 +2147,9 @@ void BotGraph::rebuildVisibility () {
|
|||
res &= 2;
|
||||
}
|
||||
}
|
||||
shift = static_cast <uint8> ((path.number % 4) << 1);
|
||||
shift = static_cast <uint8_t> ((path.number % 4) << 1);
|
||||
|
||||
m_vistable[vis.number * length () + path.number] &= static_cast <uint8> (~(3 << shift));
|
||||
m_vistable[vis.number * length () + path.number] &= ~static_cast <uint8_t> (3 << shift);
|
||||
m_vistable[vis.number * length () + path.number] |= res << shift;
|
||||
|
||||
if (!(res & 2)) {
|
||||
|
|
@ -2171,7 +2172,7 @@ bool BotGraph::isVisible (int srcIndex, int destIndex) {
|
|||
return false;
|
||||
}
|
||||
|
||||
uint8 res = m_vistable[srcIndex * length () + destIndex];
|
||||
uint8_t res = m_vistable[srcIndex * length () + destIndex];
|
||||
res >>= (destIndex % 4) << 1;
|
||||
|
||||
return !((res & 3) == 3);
|
||||
|
|
@ -2182,7 +2183,7 @@ bool BotGraph::isDuckVisible (int srcIndex, int destIndex) {
|
|||
return false;
|
||||
}
|
||||
|
||||
uint8 res = m_vistable[srcIndex * length () + destIndex];
|
||||
uint8_t res = m_vistable[srcIndex * length () + destIndex];
|
||||
res >>= (destIndex % 4) << 1;
|
||||
|
||||
return !((res & 2) == 2);
|
||||
|
|
@ -2193,7 +2194,7 @@ bool BotGraph::isStandVisible (int srcIndex, int destIndex) {
|
|||
return false;
|
||||
}
|
||||
|
||||
uint8 res = m_vistable[srcIndex * length () + destIndex];
|
||||
uint8_t res = m_vistable[srcIndex * length () + destIndex];
|
||||
res >>= (destIndex % 4) << 1;
|
||||
|
||||
return !((res & 1) == 1);
|
||||
|
|
@ -3046,7 +3047,7 @@ BotGraph::Bucket BotGraph::locateBucket (const Vector &pos) {
|
|||
};
|
||||
}
|
||||
|
||||
const SmallArray <int32> &BotGraph::getNodesInBucket (const Vector &pos) {
|
||||
const SmallArray <int32_t> &BotGraph::getNodesInBucket (const Vector &pos) {
|
||||
const auto &bucket = locateBucket (pos);
|
||||
return m_buckets[bucket.x][bucket.y][bucket.z];
|
||||
}
|
||||
|
|
@ -3084,7 +3085,7 @@ void BotGraph::updateGlobalPractice () {
|
|||
if (maxDamage > kMaxPracticeDamageValue) {
|
||||
adjustValues = true;
|
||||
}
|
||||
(practice + (i * length ()) + i)->index[team] = static_cast <int16> (bestIndex);
|
||||
(practice + (i * length ()) + i)->index[team] = static_cast <int16_t> (bestIndex);
|
||||
}
|
||||
}
|
||||
constexpr auto kHalfDamageVal = static_cast <int> (kMaxPracticeDamageValue * 0.5);
|
||||
|
|
@ -3097,7 +3098,7 @@ void BotGraph::updateGlobalPractice () {
|
|||
if (i == j) {
|
||||
continue;
|
||||
}
|
||||
(practice + (i * length ()) + j)->damage[team] = static_cast <int16> (cr::clamp (getDangerDamage (team, i, j) - kHalfDamageVal, 0, kMaxPracticeDamageValue));
|
||||
(practice + (i * length ()) + j)->damage[team] = static_cast <int16_t> (cr::clamp (getDangerDamage (team, i, j) - kHalfDamageVal, 0, kMaxPracticeDamageValue));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3232,7 +3233,7 @@ void BotGraph::setDangerValue (int team, int start, int goal, int value) {
|
|||
if (!exists (start) || !exists (goal)) {
|
||||
return;
|
||||
}
|
||||
(m_practice.data () + (start * length ()) + goal)->value[team] = static_cast <int16> (value);
|
||||
(m_practice.data () + (start * length ()) + goal)->value[team] = static_cast <int16_t> (value);
|
||||
}
|
||||
|
||||
void BotGraph::setDangerDamage (int team, int start, int goal, int value) {
|
||||
|
|
@ -3244,5 +3245,5 @@ void BotGraph::setDangerDamage (int team, int start, int goal, int value) {
|
|||
if (!exists (start) || !exists (goal)) {
|
||||
return;
|
||||
}
|
||||
(m_practice.data () + (start * length ()) + goal)->damage[team] = static_cast <int16> (value);
|
||||
(m_practice.data () + (start * length ()) + goal)->damage[team] = static_cast <int16_t> (value);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -553,7 +553,7 @@ CR_LINKAGE_C int GetEngineFunctions (enginefuncs_t *table, int *) {
|
|||
// SoundAttachToThreat() to bring the sound to the ears of the bots. Since bots have no client DLL
|
||||
// to handle this for them, such a job has to be done manually.
|
||||
|
||||
util.listenNoise (entity, sample, volume);
|
||||
sounds.listenNoise (entity, sample, volume);
|
||||
|
||||
if (game.is (GameFlags::Metamod)) {
|
||||
RETURN_META (MRES_IGNORED);
|
||||
|
|
|
|||
|
|
@ -782,7 +782,7 @@ void BotManager::listBots () {
|
|||
ctrl.msg ("%-3.5s\t%-19.16s\t%-10.12s\t%-3.4s\t%-3.4s\t%-3.4s\t%-3.5s\t%-3.8s", "index", "name", "personality", "team", "difficulty", "frags", "alive", "timeleft");
|
||||
|
||||
for (const auto &bot : bots) {
|
||||
ctrl.msg ("[%-3.1d]\t%-19.16s\t%-10.12s\t%-3.4s\t%-3.1d\t%-3.1d\t%-3.4s\t%-3.0f secs", bot->index (), bot->pev->netname.chars (), bot->m_personality == Personality::Rusher ? "rusher" : bot->m_personality == Personality::Normal ? "normal" : "careful", bot->m_team == Team::CT ? "CT" : "T", bot->m_difficulty, static_cast <int> (bot->pev->frags), bot->m_notKilled ? "yes" : "no", bot->m_stayTime - game.time ());
|
||||
ctrl.msg ("[%-3.1d]\t%-19.16s\t%-10.12s\t%-3.4s\t%-3.1d\t%-3.1d\t%-3.4s\t%-3.0f secs", bot->index (), bot->pev->netname.chars (), bot->m_personality == Personality::Rusher ? "rusher" : bot->m_personality == Personality::Normal ? "normal" : "careful", bot->m_team == Team::CT ? "CT" : "T", bot->m_difficulty, static_cast <int> (bot->pev->frags), bot->m_notKilled ? "yes" : "no", cv_rotate_bots.bool_ () ? bot->m_stayTime - game.time () : 0.0f);
|
||||
}
|
||||
ctrl.msg ("%d bots", m_bots.length ());
|
||||
}
|
||||
|
|
@ -799,7 +799,7 @@ float BotManager::getConnectTime (StringRef name, float original) {
|
|||
}
|
||||
|
||||
float BotManager::getAverageTeamKPD (bool calcForBots) {
|
||||
Twin <float, int32> calc {};
|
||||
Twin <float, int32_t> calc {};
|
||||
|
||||
for (const auto &client : util.getClients ()) {
|
||||
if (!(client.flags & ClientFlags::Used)) {
|
||||
|
|
@ -913,7 +913,7 @@ void BotManager::updateBotDifficulties () {
|
|||
|
||||
void BotManager::balanceBotDifficulties () {
|
||||
// difficulty chaning once per round (time)
|
||||
auto updateDifficulty = [] (Bot *bot, int32 offset) {
|
||||
auto updateDifficulty = [] (Bot *bot, int32_t offset) {
|
||||
bot->m_difficulty = cr::clamp (static_cast <Difficulty> (bot->m_difficulty + offset), Difficulty::Noob, Difficulty::Expert);
|
||||
};
|
||||
|
||||
|
|
@ -1080,11 +1080,9 @@ Bot::Bot (edict_t *bot, int difficulty, int personality, int team, int skin) {
|
|||
m_wantedTeam = team;
|
||||
m_wantedSkin = skin;
|
||||
|
||||
newRound ();
|
||||
}
|
||||
m_tasks.reserve (Task::Max);
|
||||
|
||||
float Bot::getFrameInterval () {
|
||||
return m_frameInterval;
|
||||
newRound ();
|
||||
}
|
||||
|
||||
float Bot::getConnectionTime () {
|
||||
|
|
@ -1126,6 +1124,24 @@ int BotManager::getAliveHumansCount () {
|
|||
return count;
|
||||
}
|
||||
|
||||
int BotManager::getPlayerPriority (edict_t *ent) {
|
||||
constexpr auto highPrio = 512;
|
||||
|
||||
// always check for only our own bots
|
||||
auto bot = bots[ent];
|
||||
|
||||
// if player just return high prio
|
||||
if (!bot) {
|
||||
return game.indexOfEntity (ent) + highPrio;
|
||||
}
|
||||
|
||||
// give bots some priority
|
||||
if (bot->m_hasC4 || bot->m_isVIP || bot->hasHostage () || bot->m_healthValue < ent->v.health) {
|
||||
return bot->entindex () + highPrio;
|
||||
}
|
||||
return bot->entindex ();
|
||||
}
|
||||
|
||||
bool BotManager::isTeamStacked (int team) {
|
||||
if (team != Team::CT && team != Team::Terrorist) {
|
||||
return false;
|
||||
|
|
@ -1422,7 +1438,7 @@ void Bot::newRound () {
|
|||
msg = BotMsg::None;
|
||||
}
|
||||
m_msgQueue.clear ();
|
||||
m_goalHistory.clear ();
|
||||
m_nodeHistory.clear ();
|
||||
m_ignoredBreakable.clear ();
|
||||
|
||||
// clear last trace
|
||||
|
|
@ -1532,13 +1548,15 @@ void Bot::updateTeamJoin () {
|
|||
if (m_startAction == BotMsg::TeamSelect) {
|
||||
m_startAction = BotMsg::None; // switch back to idle
|
||||
|
||||
char teamJoin = cv_join_team.str ()[0];
|
||||
if (m_wantedTeam == -1) {
|
||||
char teamJoin = cv_join_team.str ()[0];
|
||||
|
||||
if (teamJoin == 'C' || teamJoin == 'c') {
|
||||
m_wantedTeam = 2;
|
||||
}
|
||||
else if (teamJoin == 'T' || teamJoin == 't') {
|
||||
m_wantedTeam = 1;
|
||||
if (teamJoin == 'C' || teamJoin == 'c') {
|
||||
m_wantedTeam = 2;
|
||||
}
|
||||
else if (teamJoin == 'T' || teamJoin == 't') {
|
||||
m_wantedTeam = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_wantedTeam != 1 && m_wantedTeam != 2) {
|
||||
|
|
@ -1595,7 +1613,7 @@ void Bot::updateTeamJoin () {
|
|||
|
||||
// check for greeting other players, since we connected
|
||||
if (rg.chance (20)) {
|
||||
pushChatMessage (Chat::Hello);
|
||||
m_needToSendWelcomeChat = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -352,7 +352,7 @@ void MessageDispatcher::netMsgScoreAttrib () {
|
|||
|
||||
// if we're have bot, set the vip state
|
||||
if (bot != nullptr) {
|
||||
constexpr int32 kPlayerIsVIP = cr::bit (2);
|
||||
constexpr int32_t kPlayerIsVIP = cr::bit (2);
|
||||
|
||||
bot->m_isVIP = !!(m_args[flags].long_ & kPlayerIsVIP);
|
||||
}
|
||||
|
|
@ -492,7 +492,7 @@ MessageDispatcher::MessageDispatcher () {
|
|||
m_teamInfoCache["CT"] = Team::CT;
|
||||
}
|
||||
|
||||
int32 MessageDispatcher::add (StringRef name, int32 id) {
|
||||
int32_t MessageDispatcher::add (StringRef name, int32_t id) {
|
||||
if (!m_wanted.has (name)) {
|
||||
return id;
|
||||
}
|
||||
|
|
@ -503,7 +503,7 @@ int32 MessageDispatcher::add (StringRef name, int32 id) {
|
|||
return id;
|
||||
}
|
||||
|
||||
void MessageDispatcher::start (edict_t *ent, int32 type) {
|
||||
void MessageDispatcher::start (edict_t *ent, int32_t type) {
|
||||
reset ();
|
||||
|
||||
if (game.is (GameFlags::Metamod)) {
|
||||
|
|
@ -551,16 +551,16 @@ void MessageDispatcher::ensureMessages () {
|
|||
}
|
||||
|
||||
// re-register our message
|
||||
m_wanted.foreach ([&] (const String &key, const int32 &) {
|
||||
m_wanted.foreach ([&] (const String &key, const int32_t &) {
|
||||
add (key, GET_USER_MSG_ID (PLID, key.chars (), nullptr));
|
||||
});
|
||||
}
|
||||
|
||||
int32 MessageDispatcher::id (NetMsg msg) {
|
||||
int32_t MessageDispatcher::id (NetMsg msg) {
|
||||
return m_maps[msg];
|
||||
}
|
||||
|
||||
Bot *MessageDispatcher::pickBot (int32 index) {
|
||||
Bot *MessageDispatcher::pickBot (int32_t index) {
|
||||
const auto &client = util.getClient (m_args[index].long_ - 1);
|
||||
|
||||
// get the bot in this msg
|
||||
|
|
|
|||
382
src/navigate.cpp
382
src/navigate.cpp
|
|
@ -12,8 +12,8 @@ ConVar cv_path_danger_factor_min ("yb_path_danger_factor_min", "200", "Lower bou
|
|||
ConVar cv_path_danger_factor_max ("yb_path_danger_factor_max", "400", "Upper bound of danger factor that used to add additional danger to path based on practice.", true, 200.0f, 4800.0f);
|
||||
|
||||
int Bot::findBestGoal () {
|
||||
auto pushToHistroy = [&] (int32 goal) -> int32 {
|
||||
m_goalHistory.push (goal);
|
||||
auto pushToHistroy = [&] (int32_t goal) -> int32_t {
|
||||
m_nodeHistory.push (goal);
|
||||
return goal;
|
||||
};
|
||||
|
||||
|
|
@ -188,12 +188,9 @@ int Bot::findBestGoalWhenBombAction () {
|
|||
startTask (Task::Camp, TaskPri::Camp, kInvalidNodeIndex, timeMidBlowup, true); // push camp task on to stack
|
||||
startTask (Task::MoveToPosition, TaskPri::MoveToPosition, result, timeMidBlowup, true); // push move command
|
||||
|
||||
if (path.vis.crouch <= path.vis.stand) {
|
||||
m_campButtons |= IN_DUCK;
|
||||
}
|
||||
else {
|
||||
m_campButtons &= ~IN_DUCK;
|
||||
}
|
||||
// decide to duck or not to duck
|
||||
selectCampButtons (result);
|
||||
|
||||
if (rg.chance (90)) {
|
||||
pushChatterMessage (Chatter::DefendingBombsite);
|
||||
}
|
||||
|
|
@ -259,8 +256,7 @@ int Bot::findGoalPost (int tactic, IntArray *defensive, IntArray *offsensive) {
|
|||
postprocessGoals (graph.m_goalPoints, goalChoices);
|
||||
}
|
||||
}
|
||||
else if (tactic == 4 && !graph.m_rescuePoints.empty ()) // rescue goal
|
||||
{
|
||||
else if (tactic == 4 && !graph.m_rescuePoints.empty ()) {
|
||||
// force ct with hostage(s) to select closest rescue goal
|
||||
float minDist = kInfiniteDistance;
|
||||
int count = 0;
|
||||
|
|
@ -286,7 +282,7 @@ int Bot::findGoalPost (int tactic, IntArray *defensive, IntArray *offsensive) {
|
|||
}
|
||||
|
||||
if (!graph.exists (m_currentNodeIndex)) {
|
||||
m_currentNodeIndex = changePointIndex (findNearestNode ());
|
||||
changeNodeIndex (findNearestNode ());
|
||||
}
|
||||
|
||||
if (goalChoices[0] == kInvalidNodeIndex) {
|
||||
|
|
@ -320,7 +316,7 @@ void Bot::postprocessGoals (const IntArray &goals, int result[]) {
|
|||
for (int index = 0; index < 4; ++index) {
|
||||
auto goal = goals.random ();
|
||||
|
||||
if (searchCount <= 8 && (isBannedNode (goal) || m_prevGoalIndex == goal || ((result[0] == goal || result[1] == goal || result[2] == goal || result[3] == goal) && goals.length () > 4)) && !isOccupiedNode (goal)) {
|
||||
if (searchCount <= 8 && (m_prevGoalIndex == goal || ((result[0] == goal || result[1] == goal || result[2] == goal || result[3] == goal) && goals.length () > 4)) && !isOccupiedNode (goal)) {
|
||||
if (index > 0) {
|
||||
index--;
|
||||
}
|
||||
|
|
@ -370,13 +366,14 @@ void Bot::ignoreCollision () {
|
|||
m_prevOrigin = pev->origin;
|
||||
}
|
||||
|
||||
bool Bot::doPlayerAvoidance (const Vector &normal) {
|
||||
edict_t *hindrance = nullptr;
|
||||
float distance = cr::square (300.0f);
|
||||
void Bot::doPlayerAvoidance (const Vector &normal) {
|
||||
m_hindrance = nullptr;
|
||||
float distance = cr::square (348.0f);
|
||||
|
||||
if (getCurrentTaskId () == Task::Attack || getCurrentTaskId () == Task::SeekCover || isOnLadder ()) {
|
||||
return false;
|
||||
if (getCurrentTaskId () == Task::Attack || isOnLadder ()) {
|
||||
return;
|
||||
}
|
||||
const auto ownPrio = bots.getPlayerPriority (ent ());
|
||||
|
||||
// find nearest player to bot
|
||||
for (const auto &client : util.getClients ()) {
|
||||
|
|
@ -391,28 +388,29 @@ bool Bot::doPlayerAvoidance (const Vector &normal) {
|
|||
continue;
|
||||
}
|
||||
|
||||
// skip if it's not standing
|
||||
if (client.ent->v.flags & FL_DUCKING) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// our team, alive and not myself?
|
||||
if (client.team != m_team || client.ent == ent ()) {
|
||||
continue;
|
||||
}
|
||||
const auto otherPrio = bots.getPlayerPriority (client.ent);
|
||||
|
||||
// give some priorities to bot avoidance
|
||||
if (ownPrio > otherPrio) {
|
||||
continue;
|
||||
}
|
||||
auto nearest = client.ent->v.origin.distanceSq (pev->origin);
|
||||
|
||||
if (nearest < cr::square (pev->maxspeed) && nearest < distance) {
|
||||
hindrance = client.ent;
|
||||
m_hindrance = client.ent;
|
||||
distance = nearest;
|
||||
}
|
||||
}
|
||||
|
||||
// found somebody?
|
||||
if (!hindrance) {
|
||||
return false;
|
||||
if (game.isNullEntity (m_hindrance)) {
|
||||
return;
|
||||
}
|
||||
const float interval = getFrameInterval () * 4.0f;
|
||||
const float interval = m_frameInterval * 7.25f;
|
||||
|
||||
// use our movement angles, try to predict where we should be next frame
|
||||
Vector right, forward;
|
||||
|
|
@ -423,44 +421,39 @@ bool Bot::doPlayerAvoidance (const Vector &normal) {
|
|||
predict += right * m_strafeSpeed * interval;
|
||||
predict += pev->velocity * interval;
|
||||
|
||||
auto movedDistance = hindrance->v.origin.distanceSq (predict);
|
||||
auto nextFrameDistance = pev->origin.distanceSq (hindrance->v.origin + hindrance->v.velocity * interval);
|
||||
auto movedDistance = m_hindrance->v.origin.distanceSq (predict);
|
||||
auto nextFrameDistance = pev->origin.distanceSq (m_hindrance->v.origin + m_hindrance->v.velocity * interval);
|
||||
|
||||
// is player that near now or in future that we need to steer away?
|
||||
if (movedDistance <= cr::square (48.0f) || (distance <= cr::square (56.0f) && nextFrameDistance < distance)) {
|
||||
auto dir = (pev->origin - hindrance->v.origin).normalize2d ();
|
||||
auto dir = (pev->origin - m_hindrance->v.origin).normalize2d ();
|
||||
|
||||
// to start strafing, we have to first figure out if the target is on the left side or right side
|
||||
if ((dir | right.get2d ()) > 0.0f) {
|
||||
if ((dir | right.normalize2d ()) > 0.0f) {
|
||||
setStrafeSpeed (normal, pev->maxspeed);
|
||||
}
|
||||
else {
|
||||
setStrafeSpeed (normal, -pev->maxspeed);
|
||||
}
|
||||
if (distance < cr::square (56.0f)) {
|
||||
if ((dir | forward.get2d ()) < 0.0f) {
|
||||
|
||||
if (distance < cr::square (76.0f)) {
|
||||
if ((dir | forward.normalize2d ()) < 0.0f) {
|
||||
m_moveSpeed = -pev->maxspeed;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Bot::checkTerrain (float movedDistance, const Vector &dirNormal) {
|
||||
|
||||
// if avoiding someone do not consider stuck
|
||||
TraceResult tr {};
|
||||
m_isStuck = doPlayerAvoidance (dirNormal);
|
||||
float checkSpeed = isDucking () ? 4.0f : 10.0f;
|
||||
|
||||
if (m_isStuck) {
|
||||
resetCollision ();
|
||||
return;
|
||||
}
|
||||
m_isStuck = false;
|
||||
|
||||
// Standing still, no need to check?
|
||||
// FIXME: doesn't care for ladder movement (handled separately) should be included in some way
|
||||
if ((m_moveSpeed >= 10.0f || m_strafeSpeed >= 10.0f) && m_lastCollTime < game.time () && m_seeEnemyTime + 0.8f < game.time () && getCurrentTaskId () != Task::Attack) {
|
||||
// standing still, no need to check?
|
||||
if ((m_moveSpeed >= checkSpeed || m_strafeSpeed >= checkSpeed) && m_lastCollTime < game.time ()) {
|
||||
|
||||
// didn't we move enough previously?
|
||||
if (movedDistance < 2.0f && m_prevSpeed >= 20.0f) {
|
||||
|
|
@ -504,7 +497,7 @@ void Bot::checkTerrain (float movedDistance, const Vector &dirNormal) {
|
|||
|
||||
// bot is stuc, but not yet decided what to do?
|
||||
if (m_collisionState == CollisionState::Undecided) {
|
||||
uint32 bits = 0;
|
||||
uint32_t bits = 0;
|
||||
|
||||
if (isOnLadder ()) {
|
||||
bits |= CollisionProbe::Strafe;
|
||||
|
|
@ -515,7 +508,7 @@ void Bot::checkTerrain (float movedDistance, const Vector &dirNormal) {
|
|||
|
||||
// collision check allowed if not flying through the air
|
||||
if (isOnFloor () || isOnLadder () || isInWater ()) {
|
||||
uint32 state[kMaxCollideMoves * 2 + 1] {};
|
||||
uint32_t state[kMaxCollideMoves * 2 + 1] {};
|
||||
int i = 0;
|
||||
|
||||
Vector src {}, dst {};
|
||||
|
|
@ -623,7 +616,7 @@ void Bot::checkTerrain (float movedDistance, const Vector &dirNormal) {
|
|||
}
|
||||
}
|
||||
}
|
||||
if (pev->flags & FL_DUCKING) {
|
||||
if (isDucking ()) {
|
||||
src = pev->origin;
|
||||
}
|
||||
else {
|
||||
|
|
@ -724,13 +717,105 @@ void Bot::checkTerrain (float movedDistance, const Vector &dirNormal) {
|
|||
}
|
||||
}
|
||||
|
||||
void Bot::moveToGoal () {
|
||||
findValidNode ();
|
||||
|
||||
bool prevLadder = false;
|
||||
|
||||
if (graph.exists (m_previousNodes[0])) {
|
||||
if (graph[m_previousNodes[0]].flags & NodeFlag::Ladder) {
|
||||
prevLadder = true;
|
||||
}
|
||||
}
|
||||
|
||||
// press duck button if we need to
|
||||
if ((m_pathFlags & NodeFlag::Crouch) && !(m_pathFlags & (NodeFlag::Camp | NodeFlag::Goal))) {
|
||||
pev->button |= IN_DUCK;
|
||||
}
|
||||
m_lastUsedNodesTime = game.time ();
|
||||
|
||||
// press jump button if we need to leave the ladder
|
||||
if (!(m_pathFlags & NodeFlag::Ladder) && prevLadder && isOnFloor () && isOnLadder () && m_moveSpeed > 50.0f && pev->velocity.length () < 50.0f) {
|
||||
pev->button |= IN_JUMP;
|
||||
m_jumpTime = game.time () + 1.0f;
|
||||
}
|
||||
|
||||
if (m_pathFlags & NodeFlag::Ladder) {
|
||||
if (m_pathOrigin.z < pev->origin.z + 16.0f && !isOnLadder () && isOnFloor () && !isDucking ()) {
|
||||
if (!prevLadder) {
|
||||
m_moveSpeed = pev->origin.distance (m_pathOrigin);
|
||||
}
|
||||
else {
|
||||
m_moveSpeed = 150.0f;
|
||||
}
|
||||
if (m_moveSpeed < 150.0f) {
|
||||
m_moveSpeed = 150.0f;
|
||||
}
|
||||
else if (m_moveSpeed > pev->maxspeed) {
|
||||
m_moveSpeed = pev->maxspeed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// special movement for swimming here
|
||||
if (isInWater ()) {
|
||||
// check if we need to go forward or back press the correct buttons
|
||||
if (isInFOV (m_destOrigin - getEyesPos ()) > 90.0f) {
|
||||
pev->button |= IN_BACK;
|
||||
}
|
||||
else {
|
||||
pev->button |= IN_FORWARD;
|
||||
}
|
||||
|
||||
if (m_moveAngles.x > 60.0f) {
|
||||
pev->button |= IN_DUCK;
|
||||
}
|
||||
else if (m_moveAngles.x < -60.0f) {
|
||||
pev->button |= IN_JUMP;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Bot::translateInput () {
|
||||
if (m_duckTime >= game.time ()) {
|
||||
pev->button |= IN_DUCK;
|
||||
}
|
||||
|
||||
if (pev->button & IN_JUMP) {
|
||||
m_jumpTime = game.time ();
|
||||
}
|
||||
|
||||
if (m_jumpTime + 0.85f > game.time ()) {
|
||||
if (!isOnFloor () && !isInWater () && !isOnLadder ()) {
|
||||
pev->button |= IN_DUCK;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(pev->button & (IN_FORWARD | IN_BACK))) {
|
||||
if (m_moveSpeed > 0.0f) {
|
||||
pev->button |= IN_FORWARD;
|
||||
}
|
||||
else if (m_moveSpeed < 0.0f) {
|
||||
pev->button |= IN_BACK;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(pev->button & (IN_MOVELEFT | IN_MOVERIGHT))) {
|
||||
if (m_strafeSpeed > 0.0f) {
|
||||
pev->button |= IN_MOVERIGHT;
|
||||
}
|
||||
else if (m_strafeSpeed < 0.0f) {
|
||||
pev->button |= IN_MOVELEFT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Bot::updateNavigation () {
|
||||
// this function is a main path navigation
|
||||
|
||||
// check if we need to find a node...
|
||||
if (m_currentNodeIndex == kInvalidNodeIndex) {
|
||||
findValidNode ();
|
||||
m_pathOrigin = m_path->origin;
|
||||
|
||||
// if graph node radius non zero vary origin a bit depending on the body angles
|
||||
if (m_path->radius > 0.0f) {
|
||||
|
|
@ -749,7 +834,9 @@ bool Bot::updateNavigation () {
|
|||
// if bot's on the ground or on the ladder we're free to jump. actually setting the correct velocity is cheating.
|
||||
// pressing the jump button gives the illusion of the bot actual jumping.
|
||||
if (isOnFloor () || isOnLadder ()) {
|
||||
pev->velocity = m_desiredVelocity;
|
||||
if (m_desiredVelocity.length2d () > 0.0f) {
|
||||
pev->velocity = m_desiredVelocity + m_desiredVelocity * 0.05f;
|
||||
}
|
||||
pev->button |= IN_JUMP;
|
||||
|
||||
m_jumpFinished = true;
|
||||
|
|
@ -759,10 +846,16 @@ bool Bot::updateNavigation () {
|
|||
}
|
||||
else if (!cv_jasonmode.bool_ () && usesKnife () && isOnFloor ()) {
|
||||
selectBestWeapon ();
|
||||
|
||||
// if jump distance was big enough, cooldown a little
|
||||
if (m_jumpDistance > 180.0f) {
|
||||
startTask (Task::Pause, TaskPri::Pause, kInvalidNodeIndex, game.time () + 0.45f, false);
|
||||
}
|
||||
m_jumpDistance = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_path->flags & NodeFlag::Ladder) {
|
||||
if (m_pathFlags & NodeFlag::Ladder) {
|
||||
if (!m_pathWalk.empty ()) {
|
||||
if (m_pathWalk.hasNext ()) {
|
||||
if (graph[m_pathWalk.next ()].flags & NodeFlag::Ladder || isOnLadder ()) {
|
||||
|
|
@ -776,10 +869,10 @@ bool Bot::updateNavigation () {
|
|||
m_pathOrigin.z += pev->origin.z - m_pathOrigin.z;
|
||||
}
|
||||
if (m_pathOrigin.z > (pev->origin.z + 16.0f)) {
|
||||
m_pathOrigin = m_path->origin - Vector (0.0f, 0.0f, 16.0f);
|
||||
m_pathOrigin = m_pathOrigin - Vector (0.0f, 0.0f, 16.0f);
|
||||
}
|
||||
if (m_pathOrigin.z < (pev->origin.z - 16.0f)) {
|
||||
m_pathOrigin = m_path->origin + Vector (0.0f, 0.0f, 16.0f);
|
||||
m_pathOrigin = m_pathOrigin + Vector (0.0f, 0.0f, 16.0f);
|
||||
}
|
||||
}
|
||||
m_destOrigin = m_pathOrigin;
|
||||
|
|
@ -813,7 +906,7 @@ bool Bot::updateNavigation () {
|
|||
}
|
||||
}
|
||||
else {
|
||||
game.testHull (getEyesPos (), m_path->origin, TraceIgnore::Monsters, pev->flags & FL_DUCKING ? head_hull : human_hull, ent (), &tr);
|
||||
game.testHull (getEyesPos (), m_pathOrigin, TraceIgnore::Monsters, isDucking () ? head_hull : human_hull, ent (), &tr);
|
||||
|
||||
// someone is above or below us and is using the ladder already
|
||||
if (tr.pHit == client.ent && cr::abs (pev->origin.z - client.ent->v.origin.z) > 15.0f && (client.ent->v.movetype == MOVETYPE_FLY)) {
|
||||
|
|
@ -843,7 +936,7 @@ bool Bot::updateNavigation () {
|
|||
}
|
||||
if (foundGround) {
|
||||
if (getCurrentTaskId () != Task::MoveToPosition || !cr::fequal (getTask ()->desire, TaskPri::PlantBomb)) {
|
||||
m_currentNodeIndex = m_previousNodes[0];
|
||||
changeNodeIndex (m_previousNodes[0]);
|
||||
startTask (Task::MoveToPosition, TaskPri::PlantBomb, previousNode, 0.0f, true);
|
||||
}
|
||||
break;
|
||||
|
|
@ -856,7 +949,7 @@ bool Bot::updateNavigation () {
|
|||
}
|
||||
|
||||
// special lift handling (code merged from podbotmm)
|
||||
if (m_path->flags & NodeFlag::Lift) {
|
||||
if (m_pathFlags & NodeFlag::Lift) {
|
||||
if (updateLiftHandling ()) {
|
||||
if (!updateLiftStates ()) {
|
||||
return false;
|
||||
|
|
@ -929,16 +1022,16 @@ bool Bot::updateNavigation () {
|
|||
}
|
||||
|
||||
float desiredDistance = 8.0f;
|
||||
float nodeDistance = pev->origin.distance2d (m_pathOrigin);
|
||||
float nodeDistance = pev->origin.distance (m_pathOrigin);
|
||||
|
||||
// initialize the radius for a special node type, where the node is considered to be reached
|
||||
if (m_path->flags & NodeFlag::Lift) {
|
||||
if (m_pathFlags & NodeFlag::Lift) {
|
||||
desiredDistance = 50.0f;
|
||||
}
|
||||
else if ((pev->flags & FL_DUCKING) || (m_path->flags & NodeFlag::Goal)) {
|
||||
else if (isDucking () || (m_pathFlags & NodeFlag::Goal)) {
|
||||
desiredDistance = 25.0f;
|
||||
}
|
||||
else if (m_path->flags & NodeFlag::Ladder) {
|
||||
else if (m_pathFlags & NodeFlag::Ladder) {
|
||||
desiredDistance = 24.0f;
|
||||
}
|
||||
else if (m_currentTravelFlags & PathFlag::Jump) {
|
||||
|
|
@ -963,7 +1056,7 @@ bool Bot::updateNavigation () {
|
|||
}
|
||||
|
||||
// needs precise placement - check if we get past the point
|
||||
if (desiredDistance < 22.0f && nodeDistance < 30.0f && m_pathOrigin.distanceSq (pev->origin + pev->velocity * getFrameInterval ()) >= cr::square (nodeDistance)) {
|
||||
if (desiredDistance < 22.0f && nodeDistance < 30.0f && m_pathOrigin.distanceSq (pev->origin + pev->velocity * m_frameInterval) >= cr::square (nodeDistance)) {
|
||||
desiredDistance = nodeDistance + 1.0f;
|
||||
}
|
||||
|
||||
|
|
@ -1048,7 +1141,7 @@ bool Bot::updateLiftHandling () {
|
|||
};
|
||||
|
||||
// trace line to door
|
||||
game.testLine (pev->origin, m_path->origin, TraceIgnore::Everything, ent (), &tr);
|
||||
game.testLine (pev->origin, m_pathOrigin, TraceIgnore::Everything, ent (), &tr);
|
||||
|
||||
if (tr.flFraction < 1.0f && tr.pHit && strcmp (tr.pHit->v.classname.chars (), "func_door") == 0 && (m_liftState == LiftState::None || m_liftState == LiftState::WaitingFor || m_liftState == LiftState::LookingButtonOutside) && pev->groundentity != tr.pHit) {
|
||||
if (m_liftState == LiftState::None) {
|
||||
|
|
@ -1059,7 +1152,7 @@ bool Bot::updateLiftHandling () {
|
|||
}
|
||||
|
||||
// trace line down
|
||||
game.testLine (m_path->origin, m_path->origin + Vector (0.0f, 0.0f, -50.0f), TraceIgnore::Everything, ent (), &tr);
|
||||
game.testLine (m_path->origin, m_pathOrigin + Vector (0.0f, 0.0f, -50.0f), TraceIgnore::Everything, ent (), &tr);
|
||||
|
||||
// if trace result shows us that it is a lift
|
||||
if (!game.isNullEntity (tr.pHit) && !m_pathWalk.empty () && (strcmp (tr.pHit->v.classname.chars (), "func_door") == 0 || strcmp (tr.pHit->v.classname.chars (), "func_plat") == 0 || strcmp (tr.pHit->v.classname.chars (), "func_train") == 0) && !liftClosedDoorExists) {
|
||||
|
|
@ -1067,7 +1160,7 @@ bool Bot::updateLiftHandling () {
|
|||
if (cr::abs (pev->origin.z - tr.vecEndPos.z) < 70.0f) {
|
||||
m_liftEntity = tr.pHit;
|
||||
m_liftState = LiftState::EnteringIn;
|
||||
m_liftTravelPos = m_path->origin;
|
||||
m_liftTravelPos = m_pathOrigin;
|
||||
m_liftUsageTime = game.time () + 5.0f;
|
||||
}
|
||||
}
|
||||
|
|
@ -1289,7 +1382,7 @@ bool Bot::updateLiftHandling () {
|
|||
m_liftUsageTime = 0.0f;
|
||||
|
||||
clearSearchNodes ();
|
||||
findBestNearestNode ();
|
||||
findNextBestNode ();
|
||||
|
||||
if (graph.exists (m_previousNodes[2])) {
|
||||
findPath (m_currentNodeIndex, m_previousNodes[2], FindPath::Fast);
|
||||
|
|
@ -1302,7 +1395,7 @@ bool Bot::updateLiftHandling () {
|
|||
}
|
||||
|
||||
bool Bot::updateLiftStates () {
|
||||
if (!game.isNullEntity (m_liftEntity) && !(m_path->flags & NodeFlag::Lift)) {
|
||||
if (!game.isNullEntity (m_liftEntity) && !(m_pathFlags & NodeFlag::Lift)) {
|
||||
if (m_liftState == LiftState::TravelingBy) {
|
||||
m_liftState = LiftState::Leaving;
|
||||
m_liftUsageTime = game.time () + 10.0f;
|
||||
|
|
@ -1324,14 +1417,14 @@ bool Bot::updateLiftStates () {
|
|||
|
||||
if (graph.exists (m_previousNodes[0])) {
|
||||
if (!(graph[m_previousNodes[0]].flags & NodeFlag::Lift)) {
|
||||
changePointIndex (m_previousNodes[0]);
|
||||
changeNodeIndex (m_previousNodes[0]);
|
||||
}
|
||||
else {
|
||||
findBestNearestNode ();
|
||||
findNextBestNode ();
|
||||
}
|
||||
}
|
||||
else {
|
||||
findBestNearestNode ();
|
||||
findNextBestNode ();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
@ -1630,9 +1723,9 @@ void Bot::findPath (int srcIndex, int destIndex, FindPath pathType /*= FindPath:
|
|||
auto childRoute = &m_routes[child.index];
|
||||
|
||||
// calculate the F value as F = G + H
|
||||
float g = curRoute->g + gcalc (m_team, child.index, currentIndex);
|
||||
float h = hcalc (child.index, srcIndex, destIndex);
|
||||
float f = g + h;
|
||||
const float g = curRoute->g + gcalc (m_team, child.index, currentIndex);
|
||||
const float h = hcalc (child.index, srcIndex, destIndex);
|
||||
const float f = g + h;
|
||||
|
||||
if (childRoute->state == RouteState::New || childRoute->f > f) {
|
||||
// put the current child into open list
|
||||
|
|
@ -1674,7 +1767,7 @@ int Bot::findAimingNode (const Vector &to, int &pathLength) {
|
|||
// return the most distant node which is seen from the bot to the target and is within count
|
||||
|
||||
if (m_currentNodeIndex == kInvalidNodeIndex) {
|
||||
m_currentNodeIndex = changePointIndex (findNearestNode ());
|
||||
changeNodeIndex (findNearestNode ());
|
||||
}
|
||||
|
||||
int destIndex = graph.getNearest (to);
|
||||
|
|
@ -1704,7 +1797,7 @@ int Bot::findAimingNode (const Vector &to, int &pathLength) {
|
|||
return bestIndex;
|
||||
}
|
||||
|
||||
bool Bot::findBestNearestNode () {
|
||||
bool Bot::findNextBestNode () {
|
||||
// this function find a node in the near of the bot if bot had lost his path of pathfinder needs
|
||||
// to be restarted over again.
|
||||
|
||||
|
|
@ -1714,7 +1807,7 @@ bool Bot::findBestNearestNode () {
|
|||
int lessIndex[3] = { kInvalidNodeIndex, kInvalidNodeIndex , kInvalidNodeIndex };
|
||||
|
||||
auto &bucket = graph.getNodesInBucket (pev->origin);
|
||||
int numToSkip = cr::clamp (rg.get (0, 3), 0, static_cast <int> (bucket.length () / 2));
|
||||
int numToSkip = cr::clamp (rg.get (0, 2), 0, static_cast <int> (bucket.length () / 2));
|
||||
|
||||
for (const int at : bucket) {
|
||||
bool skip = !!(at == m_currentNodeIndex);
|
||||
|
|
@ -1748,7 +1841,7 @@ bool Bot::findBestNearestNode () {
|
|||
}
|
||||
|
||||
// ignore non-reacheable nodes...
|
||||
if (!isReachableNode (at) || isBannedNode (at)) {
|
||||
if (!isReachableNode (at)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -1809,25 +1902,14 @@ bool Bot::findBestNearestNode () {
|
|||
if (selected == kInvalidNodeIndex) {
|
||||
selected = findNearestNode ();
|
||||
}
|
||||
m_goalHistory.push (selected);
|
||||
changePointIndex (selected);
|
||||
m_nodeHistory.push (selected);
|
||||
changeNodeIndex (selected);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
float Bot::getReachTime () {
|
||||
auto task = getCurrentTaskId ();
|
||||
float estimatedTime = 0.0f;
|
||||
|
||||
switch (task) {
|
||||
case Task::Pause:
|
||||
case Task::Camp:
|
||||
case Task::Hide:
|
||||
return 0.0f;
|
||||
|
||||
default:
|
||||
estimatedTime = 2.8f; // time to reach next node
|
||||
}
|
||||
float Bot::getEstimatedNodeReachTime () {
|
||||
float estimatedTime = 2.8f;
|
||||
|
||||
// calculate 'real' time that we need to get from one node to another
|
||||
if (graph.exists (m_currentNodeIndex) && graph.exists (m_previousNodes[0])) {
|
||||
|
|
@ -1840,7 +1922,7 @@ float Bot::getReachTime () {
|
|||
else {
|
||||
estimatedTime = 3.0f * distance / pev->maxspeed;
|
||||
}
|
||||
bool longTermReachability = (m_path->flags & NodeFlag::Crouch) || (m_path->flags & NodeFlag::Ladder) || (pev->button & IN_DUCK) || (m_oldButtons & IN_DUCK);
|
||||
bool longTermReachability = (m_pathFlags & NodeFlag::Crouch) || (m_pathFlags & NodeFlag::Ladder) || (pev->button & IN_DUCK) || (m_oldButtons & IN_DUCK);
|
||||
|
||||
// check for special nodes, that can slowdown our movement
|
||||
if (longTermReachability) {
|
||||
|
|
@ -1848,7 +1930,7 @@ float Bot::getReachTime () {
|
|||
}
|
||||
estimatedTime = cr::clamp (estimatedTime, 2.0f, longTermReachability ? 8.0f : 5.0f);
|
||||
}
|
||||
return estimatedTime;
|
||||
return estimatedTime + m_frameInterval;
|
||||
}
|
||||
|
||||
void Bot::findValidNode () {
|
||||
|
|
@ -1857,11 +1939,9 @@ void Bot::findValidNode () {
|
|||
// if bot hasn't got a node we need a new one anyway or if time to get there expired get new one as well
|
||||
if (m_currentNodeIndex == kInvalidNodeIndex) {
|
||||
clearSearchNodes ();
|
||||
findBestNearestNode ();
|
||||
|
||||
m_pathOrigin = m_path->origin;
|
||||
findNextBestNode ();
|
||||
}
|
||||
else if (m_navTimeset + getReachTime () < game.time () && game.isNullEntity (m_enemy)) {
|
||||
else if (m_navTimeset + getEstimatedNodeReachTime () < game.time () && game.isNullEntity (m_enemy)) {
|
||||
|
||||
// increase danager for both teams
|
||||
for (int team = Team::Terrorist; team < kGameTeamNum; ++team) {
|
||||
|
|
@ -1880,13 +1960,11 @@ void Bot::findValidNode () {
|
|||
graph.setDangerDamage (m_team, m_currentNodeIndex, m_currentNodeIndex, damageValue);
|
||||
}
|
||||
clearSearchNodes ();
|
||||
findBestNearestNode ();
|
||||
|
||||
m_pathOrigin = m_path->origin;
|
||||
findNextBestNode ();
|
||||
}
|
||||
}
|
||||
|
||||
int Bot::changePointIndex (int index) {
|
||||
int Bot::changeNodeIndex (int index) {
|
||||
if (index == kInvalidNodeIndex) {
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1896,11 +1974,14 @@ int Bot::changePointIndex (int index) {
|
|||
m_previousNodes[0] = m_currentNodeIndex;
|
||||
|
||||
m_currentNodeIndex = index;
|
||||
|
||||
m_navTimeset = game.time ();
|
||||
m_collideTime = game.time ();
|
||||
|
||||
m_path = &graph[index];
|
||||
m_path = &graph[m_currentNodeIndex];
|
||||
m_pathFlags = m_path->flags;
|
||||
|
||||
m_pathOrigin = m_path->origin;
|
||||
|
||||
return m_currentNodeIndex; // to satisfy static-code analyzers
|
||||
}
|
||||
|
||||
|
|
@ -2004,7 +2085,7 @@ int Bot::findDefendNode (const Vector &origin) {
|
|||
// provides enough cover point, and is far away from the defending position
|
||||
|
||||
if (m_currentNodeIndex == kInvalidNodeIndex) {
|
||||
m_currentNodeIndex = changePointIndex (findNearestNode ());
|
||||
changeNodeIndex (findNearestNode ());
|
||||
}
|
||||
TraceResult tr {};
|
||||
|
||||
|
|
@ -2020,7 +2101,7 @@ int Bot::findDefendNode (const Vector &origin) {
|
|||
int srcIndex = m_currentNodeIndex;
|
||||
|
||||
// max search distance
|
||||
const int kMaxDistance = 128 * bots.getBotCount ();
|
||||
const int kMaxDistance = cr::clamp (148 * bots.getBotCount (), 256, 1024);
|
||||
|
||||
// some of points not found, return random one
|
||||
if (srcIndex == kInvalidNodeIndex || posIndex == kInvalidNodeIndex) {
|
||||
|
|
@ -2177,7 +2258,7 @@ int Bot::findCoverNode (float maxDistance) {
|
|||
}
|
||||
|
||||
// ensure we're on valid point
|
||||
changePointIndex (srcIndex);
|
||||
changeNodeIndex (srcIndex);
|
||||
|
||||
// find the best node now
|
||||
for (int i = 0; i < graph.length (); ++i) {
|
||||
|
|
@ -2207,35 +2288,35 @@ int Bot::findCoverNode (float maxDistance) {
|
|||
continue;
|
||||
}
|
||||
|
||||
if (distance > minDistance[0]) {
|
||||
if (distance < minDistance[0]) {
|
||||
nodeIndex[0] = i;
|
||||
minDistance[0] = distance;
|
||||
}
|
||||
else if (distance > minDistance[1]) {
|
||||
else if (distance < minDistance[1]) {
|
||||
nodeIndex[1] = i;
|
||||
minDistance[1] = distance;
|
||||
}
|
||||
else if (distance > minDistance[2]) {
|
||||
else if (distance < minDistance[2]) {
|
||||
nodeIndex[2] = i;
|
||||
minDistance[2] = distance;
|
||||
}
|
||||
else if (distance > minDistance[3]) {
|
||||
else if (distance < minDistance[3]) {
|
||||
nodeIndex[3] = i;
|
||||
minDistance[3] = distance;
|
||||
}
|
||||
else if (distance > minDistance[4]) {
|
||||
else if (distance < minDistance[4]) {
|
||||
nodeIndex[4] = i;
|
||||
minDistance[4] = distance;
|
||||
}
|
||||
else if (distance > minDistance[5]) {
|
||||
else if (distance < minDistance[5]) {
|
||||
nodeIndex[5] = i;
|
||||
minDistance[5] = distance;
|
||||
}
|
||||
else if (distance > minDistance[6]) {
|
||||
else if (distance < minDistance[6]) {
|
||||
nodeIndex[6] = i;
|
||||
minDistance[6] = distance;
|
||||
}
|
||||
else if (distance > minDistance[7]) {
|
||||
else if (distance < minDistance[7]) {
|
||||
nodeIndex[7] = i;
|
||||
minDistance[7] = distance;
|
||||
}
|
||||
|
|
@ -2411,7 +2492,7 @@ bool Bot::advanceMovement () {
|
|||
}
|
||||
// check if bot is going to jump
|
||||
bool willJump = false;
|
||||
float jumpDistance = 0.0f;
|
||||
m_jumpDistance = 0.0f;
|
||||
|
||||
Vector src;
|
||||
Vector dst;
|
||||
|
|
@ -2420,15 +2501,15 @@ bool Bot::advanceMovement () {
|
|||
if (m_pathWalk.hasNext ()) {
|
||||
auto nextIndex = m_pathWalk.next ();
|
||||
|
||||
const Path &path = graph[destIndex];
|
||||
const Path &next = graph[nextIndex];
|
||||
const auto &path = graph[destIndex];
|
||||
const auto &next = graph[nextIndex];
|
||||
|
||||
for (const auto &link : path.links) {
|
||||
if (link.index == nextIndex && (link.flags & PathFlag::Jump)) {
|
||||
src = path.origin;
|
||||
dst = next.origin;
|
||||
|
||||
jumpDistance = path.origin.distance (next.origin);
|
||||
m_jumpDistance = path.origin.distance (next.origin);
|
||||
willJump = true;
|
||||
|
||||
break;
|
||||
|
|
@ -2437,14 +2518,14 @@ bool Bot::advanceMovement () {
|
|||
}
|
||||
|
||||
// is there a jump node right ahead and do we need to draw out the light weapon ?
|
||||
if (willJump && !usesKnife () && m_currentWeapon != Weapon::Scout && !m_isReloading && !usesPistol () && (jumpDistance > 200.0f || (dst.z - 32.0f > src.z && jumpDistance > 150.0f)) && !(m_states & (Sense::SeeingEnemy | Sense::SuspectEnemy))) {
|
||||
selectWeaponByName ("weapon_knife"); // draw out the knife if we needed
|
||||
if (willJump && !usesKnife () && m_currentWeapon != Weapon::Scout && !m_isReloading && !usesPistol () && (m_jumpDistance > 175.0f || (dst.z - 32.0f > src.z && m_jumpDistance > 135.0f)) && !(m_states & Sense::SeeingEnemy)) {
|
||||
selectWeaponById (Weapon::Knife); // draw out the knife if we needed
|
||||
}
|
||||
|
||||
// bot not already on ladder but will be soon?
|
||||
if ((graph[destIndex].flags & NodeFlag::Ladder) && !isOnLadder ()) {
|
||||
// get ladder nodes used by other (first moving) bots
|
||||
|
||||
// get ladder nodes used by other (first moving) bots
|
||||
for (const auto &other : bots) {
|
||||
// if another bot uses this ladder, wait 3 secs
|
||||
if (other.get () != this && other->m_notKilled && other->m_currentNodeIndex == destIndex) {
|
||||
|
|
@ -2454,10 +2535,9 @@ bool Bot::advanceMovement () {
|
|||
}
|
||||
}
|
||||
}
|
||||
changePointIndex (destIndex);
|
||||
changeNodeIndex (destIndex);
|
||||
}
|
||||
}
|
||||
m_pathOrigin = m_path->origin;
|
||||
|
||||
// if wayzone radius non zero vary origin a bit depending on the body angles
|
||||
if (m_path->radius > 0.0f) {
|
||||
|
|
@ -2484,7 +2564,7 @@ bool Bot::cantMoveForward (const Vector &normal, TraceResult *tr) {
|
|||
// first do a trace from the bot's eyes forward...
|
||||
auto src = getEyesPos ();
|
||||
auto forward = src + normal * 24.0f;
|
||||
auto right = Vector (0.0f, pev->angles.y, 0.0f).right ();
|
||||
const auto &right = Vector (0.0f, pev->angles.y, 0.0f).right ();
|
||||
|
||||
bool traceResult = false;
|
||||
|
||||
|
|
@ -2531,7 +2611,7 @@ bool Bot::cantMoveForward (const Vector &normal, TraceResult *tr) {
|
|||
}
|
||||
|
||||
// now check below waist
|
||||
if (pev->flags & FL_DUCKING) {
|
||||
if (isDucking ()) {
|
||||
src = pev->origin + Vector (0.0f, 0.0f, -19.0f + 19.0f);
|
||||
forward = src + Vector (0.0f, 0.0f, 10.0f) + normal * 24.0f;
|
||||
|
||||
|
|
@ -2646,7 +2726,7 @@ bool Bot::canJumpUp (const Vector &normal) {
|
|||
if (!isOnFloor () && (isOnLadder () || !isInWater ())) {
|
||||
return false;
|
||||
}
|
||||
auto right = Vector (0.0f, pev->angles.y, 0.0f).right (); // convert current view angle to vectors for traceline math...
|
||||
const auto &right = Vector (0.0f, pev->angles.y, 0.0f).right (); // convert current view angle to vectors for traceline math...
|
||||
|
||||
// check for normal jump height first...
|
||||
auto src = pev->origin + Vector (0.0f, 0.0f, -36.0f + 45.0f);
|
||||
|
|
@ -2793,7 +2873,7 @@ bool Bot::canDuckUnder (const Vector &normal) {
|
|||
Vector baseHeight;
|
||||
|
||||
// use center of the body first...
|
||||
if (pev->flags & FL_DUCKING) {
|
||||
if (isDucking ()) {
|
||||
baseHeight = pev->origin + Vector (0.0f, 0.0f, -17.0f);
|
||||
}
|
||||
else {
|
||||
|
|
@ -2812,7 +2892,7 @@ bool Bot::canDuckUnder (const Vector &normal) {
|
|||
}
|
||||
|
||||
// convert current view angle to vectors for TraceLine math...
|
||||
auto right = Vector (0.0f, pev->angles.y, 0.0f).right ();
|
||||
const auto &right = Vector (0.0f, pev->angles.y, 0.0f).right ();
|
||||
|
||||
// now check same height to one side of the bot...
|
||||
src = baseHeight + right * 16.0f;
|
||||
|
|
@ -3008,16 +3088,17 @@ void Bot::changeYaw (float speed) {
|
|||
pev->angles.y = pev->v_angle.y;
|
||||
}
|
||||
|
||||
int Bot::findCampingDirection () {
|
||||
int Bot::getRandomCampDir () {
|
||||
// find a good node to look at when camping
|
||||
|
||||
if (m_currentNodeIndex == kInvalidNodeIndex) {
|
||||
m_currentNodeIndex = changePointIndex (findNearestNode ());
|
||||
changeNodeIndex (findNearestNode ());
|
||||
}
|
||||
constexpr int kMaxNodesToSearch = 5;
|
||||
|
||||
int count = 0, indices[3] {};
|
||||
float distTab[3] {};
|
||||
uint16 visibility[3] {};
|
||||
int count = 0, indices[kMaxNodesToSearch] {};
|
||||
float distTab[kMaxNodesToSearch] {};
|
||||
uint16_t visibility[kMaxNodesToSearch] {};
|
||||
|
||||
int currentNode = m_currentNodeIndex;
|
||||
|
||||
|
|
@ -3025,9 +3106,9 @@ int Bot::findCampingDirection () {
|
|||
if (currentNode == i || !graph.isVisible (currentNode, i)) {
|
||||
continue;
|
||||
}
|
||||
const Path &path = graph[i];
|
||||
const auto &path = graph[i];
|
||||
|
||||
if (count < 3) {
|
||||
if (count < kMaxNodesToSearch) {
|
||||
indices[count] = i;
|
||||
|
||||
distTab[count] = pev->origin.distanceSq (path.origin);
|
||||
|
|
@ -3037,9 +3118,9 @@ int Bot::findCampingDirection () {
|
|||
}
|
||||
else {
|
||||
float distance = pev->origin.distanceSq (path.origin);
|
||||
uint16 visBits = path.vis.crouch + path.vis.stand;
|
||||
uint16_t visBits = path.vis.crouch + path.vis.stand;
|
||||
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
for (int j = 0; j < kMaxNodesToSearch; ++j) {
|
||||
if (visBits >= visibility[j] && distance > distTab[j]) {
|
||||
indices[j] = i;
|
||||
|
||||
|
|
@ -3077,7 +3158,7 @@ void Bot::updateLookAngles () {
|
|||
|
||||
// adjust all body and view angles to face an absolute vector
|
||||
Vector direction = (m_lookAt - getEyesPos ()).angles ();
|
||||
direction.x *= -1.0f; // invert for engine
|
||||
direction.x = -direction.x; // invert for engine
|
||||
|
||||
direction.clampAngles ();
|
||||
|
||||
|
|
@ -3089,18 +3170,14 @@ void Bot::updateLookAngles () {
|
|||
return;
|
||||
}
|
||||
|
||||
if (m_difficulty == Difficulty::Expert && (m_aimFlags & AimFlags::Enemy) && (m_wantsToFire || usesSniper ()) && m_kpdRatio < 1.0f && m_healthValue < 50.0f) {
|
||||
pev->v_angle = direction;
|
||||
updateBodyAngles ();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
float accelerate = 3000.0f;
|
||||
float stiffness = 200.0f;
|
||||
float damping = 25.0f;
|
||||
|
||||
if ((m_aimFlags & (AimFlags::Enemy | AimFlags::Entity | AimFlags::Grenade)) && m_difficulty > Difficulty::Hard) {
|
||||
if (((m_aimFlags & (AimFlags::Enemy | AimFlags::Entity | AimFlags::Grenade)) || m_wantsToFire) && m_difficulty > Difficulty::Normal) {
|
||||
if (m_difficulty == Difficulty::Expert) {
|
||||
accelerate += 600.0f;
|
||||
}
|
||||
stiffness += 100.0f;
|
||||
damping += 5.0f;
|
||||
}
|
||||
|
|
@ -3275,14 +3352,10 @@ bool Bot::isOccupiedNode (int index, bool needZeroVelocity) {
|
|||
}
|
||||
auto bot = bots[client.ent];
|
||||
|
||||
if (bot == nullptr || bot == this || !bot->m_notKilled || bot->getTask ()->data == index) {
|
||||
if (bot == nullptr || bot == this || !bot->m_notKilled) {
|
||||
continue;
|
||||
}
|
||||
auto occupyId = util.getShootingCone (bot->ent (), pev->origin) >= 0.7f ? bot->m_previousNodes[0] : bot->m_currentNodeIndex;
|
||||
|
||||
if (index == occupyId) {
|
||||
return true;
|
||||
}
|
||||
return index == bot->m_currentNodeIndex || bot->getTask ()->data == index;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
@ -3366,10 +3439,17 @@ bool Bot::isReachableNode (int index) {
|
|||
}
|
||||
|
||||
bool Bot::isBannedNode (int index) {
|
||||
if (graph.exists (cv_debug_goal.int_ ())) {
|
||||
if (graph.exists (cv_debug_goal.int_ ()) || !graph.exists (index)) {
|
||||
return false;
|
||||
}
|
||||
for (const auto &node : m_goalHistory) {
|
||||
const auto &bucket = graph.getNodesInBucket (graph[index].origin);
|
||||
|
||||
// too few nodes in bucket near location, do not ban anything
|
||||
if (bucket.length <int> () <= kMaxNodeLinks) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const auto &node : m_nodeHistory) {
|
||||
if (node == index) {
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
181
src/sounds.cpp
Normal file
181
src/sounds.cpp
Normal file
|
|
@ -0,0 +1,181 @@
|
|||
//
|
||||
// YaPB - Counter-Strike Bot based on PODBot by Markus Klinge.
|
||||
// Copyright © 2004-2023 YaPB Project <yapb@jeefo.net>.
|
||||
//
|
||||
// SPDX-License-Identifier: MIT
|
||||
//
|
||||
|
||||
#include <yapb.h>
|
||||
|
||||
BotSounds::BotSounds () {
|
||||
// register noise cache
|
||||
m_noiseCache["player/bhit"] = Noise::NeedHandle | Noise::HitFall;
|
||||
m_noiseCache["player/head"] = Noise::NeedHandle | Noise::HitFall;
|
||||
m_noiseCache["items/gunpi"] = Noise::NeedHandle | Noise::Pickup;
|
||||
m_noiseCache["items/9mmcl"] = Noise::NeedHandle | Noise::Ammo;
|
||||
m_noiseCache["weapons/zoo"] = Noise::NeedHandle | Noise::Zoom;
|
||||
m_noiseCache["hostage/hos"] = Noise::NeedHandle | Noise::Hostage;
|
||||
m_noiseCache["debris/bust"] = Noise::NeedHandle | Noise::Broke;
|
||||
m_noiseCache["doors/doorm"] = Noise::NeedHandle | Noise::Door;
|
||||
m_noiseCache["weapons/c4_"] = Noise::NeedHandle | Noise::Defuse;
|
||||
}
|
||||
|
||||
void BotSounds::listenNoise (edict_t *ent, StringRef sample, float volume) {
|
||||
// this function called by the sound hooking code (in emit_sound) enters the played sound into the array associated with the entity
|
||||
|
||||
if (game.isNullEntity (ent) || sample.empty ()) {
|
||||
return;
|
||||
}
|
||||
const auto &origin = game.getEntityOrigin (ent);
|
||||
|
||||
// something wrong with sound...
|
||||
if (origin.empty ()) {
|
||||
return;
|
||||
}
|
||||
auto noise = m_noiseCache[sample.substr (0, 11)];
|
||||
|
||||
// we're not handling theese
|
||||
if (!(noise & Noise::NeedHandle)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// find nearest player to sound origin
|
||||
auto findNearbyClient = [&origin] () {
|
||||
float nearest = kInfiniteDistance;
|
||||
Client *result = nullptr;
|
||||
|
||||
// loop through all players
|
||||
for (auto &client : util.getClients ()) {
|
||||
if (!(client.flags & ClientFlags::Used) || !(client.flags & ClientFlags::Alive)) {
|
||||
continue;
|
||||
}
|
||||
auto distance = client.origin.distanceSq (origin);
|
||||
|
||||
// now find nearest player
|
||||
if (distance < nearest) {
|
||||
result = &client;
|
||||
nearest = distance;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
};
|
||||
auto client = findNearbyClient ();
|
||||
|
||||
// update noise stats
|
||||
auto registerNoise = [&origin, &client, &volume] (float distance, float lasting) {
|
||||
client->noise.dist = distance * volume;
|
||||
client->noise.last = game.time () + lasting;
|
||||
client->noise.pos = origin;
|
||||
};
|
||||
|
||||
// client wasn't found
|
||||
if (!client) {
|
||||
return;
|
||||
}
|
||||
|
||||
// hit/fall sound?
|
||||
if (noise & Noise::HitFall) {
|
||||
registerNoise (768.0f, 0.52f);
|
||||
}
|
||||
|
||||
// weapon pickup?
|
||||
else if (noise & Noise::Pickup) {
|
||||
registerNoise (768.0f, 0.45f);
|
||||
}
|
||||
|
||||
// sniper zooming?
|
||||
else if (noise & Noise::Zoom) {
|
||||
registerNoise (512.0f, 0.10f);
|
||||
}
|
||||
|
||||
// ammo pickup?
|
||||
else if (noise & Noise::Ammo) {
|
||||
registerNoise (512.0f, 0.25f);
|
||||
}
|
||||
|
||||
// ct used hostage?
|
||||
else if (noise & Noise::Hostage) {
|
||||
registerNoise (1024.0f, 5.00);
|
||||
}
|
||||
|
||||
// broke something?
|
||||
else if (noise & Noise::Broke) {
|
||||
registerNoise (1024.0f, 2.00f);
|
||||
}
|
||||
|
||||
// someone opened a door
|
||||
else if (noise & Noise::Door) {
|
||||
registerNoise (1024.0f, 3.00f);
|
||||
}
|
||||
|
||||
// some one started to defuse
|
||||
else if ((noise & Noise::Defuse) && sample[11] == 'd') {
|
||||
registerNoise (512.0f, 0.5f);
|
||||
}
|
||||
}
|
||||
|
||||
void BotSounds::simulateNoise (int playerIndex) {
|
||||
// this function tries to simulate playing of sounds to let the bots hear sounds which aren't
|
||||
// captured through server sound hooking
|
||||
|
||||
if (playerIndex < 0 || playerIndex >= game.maxClients ()) {
|
||||
return; // reliability check
|
||||
}
|
||||
auto &client = util.getClient (playerIndex);
|
||||
ClientNoise noise {};
|
||||
|
||||
auto buttons = client.ent->v.button | client.ent->v.oldbuttons;
|
||||
|
||||
// pressed attack button?
|
||||
if (buttons & IN_ATTACK) {
|
||||
noise.dist = 2048.0f;
|
||||
noise.last = game.time () + 0.3f;
|
||||
}
|
||||
|
||||
// pressed used button?
|
||||
else if (buttons & IN_USE) {
|
||||
noise.dist = 512.0f;
|
||||
noise.last = game.time () + 0.5f;
|
||||
}
|
||||
|
||||
// pressed reload button?
|
||||
else if (buttons & IN_RELOAD) {
|
||||
noise.dist = 512.0f;
|
||||
noise.last = game.time () + 0.5f;
|
||||
}
|
||||
|
||||
// uses ladder?
|
||||
else if (client.ent->v.movetype == MOVETYPE_FLY) {
|
||||
if (cr::abs (client.ent->v.velocity.z) > 50.0f) {
|
||||
noise.dist = 1024.0f;
|
||||
noise.last = game.time () + 0.3f;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (mp_footsteps.bool_ ()) {
|
||||
// moves fast enough?
|
||||
noise.dist = 1280.0f * (client.ent->v.velocity.length2d () / 260.0f);
|
||||
noise.last = game.time () + 0.3f;
|
||||
}
|
||||
}
|
||||
|
||||
if (noise.dist <= 0.0f) {
|
||||
return; // didn't issue sound?
|
||||
}
|
||||
|
||||
// some sound already associated
|
||||
if (client.noise.last > game.time ()) {
|
||||
if (client.noise.dist <= noise.dist) {
|
||||
// override it with new
|
||||
client.noise.dist = noise.dist;
|
||||
client.noise.last = noise.last;
|
||||
client.noise.pos = client.ent->v.origin;
|
||||
}
|
||||
}
|
||||
else if (!cr::fzero (noise.last)) {
|
||||
// just remember it
|
||||
client.noise.dist = noise.dist;
|
||||
client.noise.last = noise.last;
|
||||
client.noise.pos = client.ent->v.origin;
|
||||
}
|
||||
}
|
||||
195
src/support.cpp
195
src/support.cpp
|
|
@ -54,16 +54,6 @@ BotSupport::BotSupport () {
|
|||
m_tags.emplace ("(", ")");
|
||||
m_tags.emplace (")", "(");
|
||||
|
||||
// register noise cache
|
||||
m_noiseCache["player/bhit"] = Noise::NeedHandle | Noise::HitFall;
|
||||
m_noiseCache["player/head"] = Noise::NeedHandle | Noise::HitFall;
|
||||
m_noiseCache["items/gunpi"] = Noise::NeedHandle | Noise::Pickup;
|
||||
m_noiseCache["items/9mmcl"] = Noise::NeedHandle | Noise::Ammo;
|
||||
m_noiseCache["weapons/zoo"] = Noise::NeedHandle | Noise::Zoom;
|
||||
m_noiseCache["hostage/hos"] = Noise::NeedHandle | Noise::Hostage;
|
||||
m_noiseCache["debris/bust"] = Noise::NeedHandle | Noise::Broke;
|
||||
m_noiseCache["doors/doorm"] = Noise::NeedHandle | Noise::Door;
|
||||
|
||||
// register weapon aliases
|
||||
m_weaponAlias[Weapon::USP] = "usp"; // HK USP .45 Tactical
|
||||
m_weaponAlias[Weapon::Glock18] = "glock"; // Glock18 Select Fire
|
||||
|
|
@ -375,161 +365,6 @@ bool BotSupport::findNearestPlayer (void **pvHolder, edict_t *to, float searchDi
|
|||
return true;
|
||||
}
|
||||
|
||||
void BotSupport::listenNoise (edict_t *ent, StringRef sample, float volume) {
|
||||
// this function called by the sound hooking code (in emit_sound) enters the played sound into the array associated with the entity
|
||||
|
||||
if (game.isNullEntity (ent) || sample.empty ()) {
|
||||
return;
|
||||
}
|
||||
const auto &origin = game.getEntityOrigin (ent);
|
||||
|
||||
// something wrong with sound...
|
||||
if (origin.empty ()) {
|
||||
return;
|
||||
}
|
||||
auto noise = m_noiseCache[sample.substr (0, 11)];
|
||||
|
||||
// we're not handling theese
|
||||
if (!(noise & Noise::NeedHandle)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// find nearest player to sound origin
|
||||
auto findNearbyClient = [&origin] () {
|
||||
float nearest = kInfiniteDistance;
|
||||
Client *result = nullptr;
|
||||
|
||||
// loop through all players
|
||||
for (auto &client : util.getClients ()) {
|
||||
if (!(client.flags & ClientFlags::Used) || !(client.flags & ClientFlags::Alive)) {
|
||||
continue;
|
||||
}
|
||||
auto distance = client.origin.distanceSq (origin);
|
||||
|
||||
// now find nearest player
|
||||
if (distance < nearest) {
|
||||
result = &client;
|
||||
nearest = distance;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
};
|
||||
auto client = findNearbyClient ();
|
||||
|
||||
// update noise stats
|
||||
auto registerNoise = [&origin, &client, &volume] (float distance, float lasting) {
|
||||
client->noise.dist = distance * volume;
|
||||
client->noise.last = game.time () + lasting;
|
||||
client->noise.pos = origin;
|
||||
};
|
||||
|
||||
// client wasn't found
|
||||
if (!client) {
|
||||
return;
|
||||
}
|
||||
|
||||
// hit/fall sound?
|
||||
if (noise & Noise::HitFall) {
|
||||
registerNoise (768.0f, 0.52f);
|
||||
}
|
||||
|
||||
// weapon pickup?
|
||||
else if (noise & Noise::Pickup) {
|
||||
registerNoise (768.0f, 0.45f);
|
||||
}
|
||||
|
||||
// sniper zooming?
|
||||
else if (noise & Noise::Zoom) {
|
||||
registerNoise (512.0f, 0.10f);
|
||||
}
|
||||
|
||||
// ammo pickup?
|
||||
else if (noise & Noise::Ammo) {
|
||||
registerNoise (512.0f, 0.25f);
|
||||
}
|
||||
|
||||
// ct used hostage?
|
||||
else if (noise & Noise::Hostage) {
|
||||
registerNoise (1024.0f, 5.00);
|
||||
}
|
||||
|
||||
// broke something?
|
||||
else if (noise & Noise::Broke) {
|
||||
registerNoise (1024.0f, 2.00f);
|
||||
}
|
||||
|
||||
// someone opened a door
|
||||
else if (noise & Noise::Door) {
|
||||
registerNoise (1024.0f, 3.00f);
|
||||
}
|
||||
}
|
||||
|
||||
void BotSupport::simulateNoise (int playerIndex) {
|
||||
// this function tries to simulate playing of sounds to let the bots hear sounds which aren't
|
||||
// captured through server sound hooking
|
||||
|
||||
if (playerIndex < 0 || playerIndex >= game.maxClients ()) {
|
||||
return; // reliability check
|
||||
}
|
||||
Client &client = m_clients[playerIndex];
|
||||
ClientNoise noise {};
|
||||
|
||||
auto buttons = client.ent->v.button | client.ent->v.oldbuttons;
|
||||
|
||||
// pressed attack button?
|
||||
if (buttons & IN_ATTACK) {
|
||||
noise.dist = 2048.0f;
|
||||
noise.last = game.time () + 0.3f;
|
||||
}
|
||||
|
||||
// pressed used button?
|
||||
else if (buttons & IN_USE) {
|
||||
noise.dist = 512.0f;
|
||||
noise.last = game.time () + 0.5f;
|
||||
}
|
||||
|
||||
// pressed reload button?
|
||||
else if (buttons & IN_RELOAD) {
|
||||
noise.dist = 512.0f;
|
||||
noise.last = game.time () + 0.5f;
|
||||
}
|
||||
|
||||
// uses ladder?
|
||||
else if (client.ent->v.movetype == MOVETYPE_FLY) {
|
||||
if (cr::abs (client.ent->v.velocity.z) > 50.0f) {
|
||||
noise.dist = 1024.0f;
|
||||
noise.last = game.time () + 0.3f;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (mp_footsteps.bool_ ()) {
|
||||
// moves fast enough?
|
||||
noise.dist = 1280.0f * (client.ent->v.velocity.length2d () / 260.0f);
|
||||
noise.last = game.time () + 0.3f;
|
||||
}
|
||||
}
|
||||
|
||||
if (noise.dist <= 0.0f) {
|
||||
return; // didn't issue sound?
|
||||
}
|
||||
|
||||
// some sound already associated
|
||||
if (client.noise.last > game.time ()) {
|
||||
if (client.noise.dist <= noise.dist) {
|
||||
// override it with new
|
||||
client.noise.dist = noise.dist;
|
||||
client.noise.last = noise.last;
|
||||
client.noise.pos = client.ent->v.origin;
|
||||
}
|
||||
}
|
||||
else if (!cr::fzero (noise.last)) {
|
||||
// just remember it
|
||||
client.noise.dist = noise.dist;
|
||||
client.noise.last = noise.last;
|
||||
client.noise.pos = client.ent->v.origin;
|
||||
}
|
||||
}
|
||||
|
||||
void BotSupport::updateClients () {
|
||||
|
||||
// record some stats of all players on the server
|
||||
|
|
@ -550,7 +385,7 @@ void BotSupport::updateClients () {
|
|||
|
||||
if (client.flags & ClientFlags::Alive) {
|
||||
client.origin = player->v.origin;
|
||||
simulateNoise (i);
|
||||
sounds.simulateNoise (i);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
|
@ -703,24 +538,24 @@ String BotSupport::getCurrentDateTime () {
|
|||
return String (timebuf);
|
||||
}
|
||||
|
||||
int32 BotSupport::sendTo (int socket, const void *message, size_t length, int flags, const sockaddr *dest, int destLength) {
|
||||
const auto send = [&] (const Twin <const uint8 *, size_t> &msg) -> int32 {
|
||||
int32_t BotSupport::sendTo (int socket, const void *message, size_t length, int flags, const sockaddr *dest, int destLength) {
|
||||
const auto send = [&] (const Twin <const uint8_t *, size_t> &msg) -> int32_t {
|
||||
return Socket::sendto (socket, msg.first, msg.second, flags, dest, destLength);
|
||||
};
|
||||
|
||||
auto packet = reinterpret_cast <const uint8 *> (message);
|
||||
auto packet = reinterpret_cast <const uint8_t *> (message);
|
||||
|
||||
// player replies response
|
||||
if (length > 5 && packet[0] == 0xff && packet[1] == 0xff && packet[2] == 0xff && packet[3] == 0xff) {
|
||||
|
||||
if (packet[4] == 'D') {
|
||||
QueryBuffer buffer (packet, length, 5);
|
||||
auto count = buffer.read <uint8> ();
|
||||
auto count = buffer.read <uint8_t> ();
|
||||
|
||||
for (uint8 i = 0; i < count; ++i) {
|
||||
buffer.skip <uint8> (); // number
|
||||
for (uint8_t i = 0; i < count; ++i) {
|
||||
buffer.skip <uint8_t> (); // number
|
||||
auto name = buffer.readString (); // name
|
||||
buffer.skip <int32> (); // score
|
||||
buffer.skip <int32_t> (); // score
|
||||
|
||||
auto ctime = buffer.read <float> (); // override connection time
|
||||
buffer.write <float> (bots.getConnectTime (name, ctime));
|
||||
|
|
@ -729,17 +564,17 @@ int32 BotSupport::sendTo (int socket, const void *message, size_t length, int fl
|
|||
}
|
||||
else if (packet[4] == 'I') {
|
||||
QueryBuffer buffer (packet, length, 5);
|
||||
buffer.skip <uint8> (); // protocol
|
||||
buffer.skip <uint8_t> (); // protocol
|
||||
|
||||
// skip server name, folder, map game
|
||||
for (size_t i = 0; i < 4; ++i) {
|
||||
buffer.skipString ();
|
||||
}
|
||||
buffer.skip <short> (); // steam app id
|
||||
buffer.skip <uint8> (); // players
|
||||
buffer.skip <uint8> (); // maxplayers
|
||||
buffer.skip <uint8> (); // bots
|
||||
buffer.write <uint8> (0); // zero out bot count
|
||||
buffer.skip <uint8_t> (); // players
|
||||
buffer.skip <uint8_t> (); // maxplayers
|
||||
buffer.skip <uint8_t> (); // bots
|
||||
buffer.write <uint8_t> (0); // zero out bot count
|
||||
|
||||
return send (buffer.data ());
|
||||
}
|
||||
|
|
@ -747,7 +582,7 @@ int32 BotSupport::sendTo (int socket, const void *message, size_t length, int fl
|
|||
QueryBuffer buffer (packet, length, 5);
|
||||
|
||||
buffer.shiftToEnd (); // shift to the end of buffer
|
||||
buffer.write <uint8> (0); // zero out bot count
|
||||
buffer.write <uint8_t> (0); // zero out bot count
|
||||
|
||||
return send (buffer.data ());
|
||||
}
|
||||
|
|
@ -755,7 +590,7 @@ int32 BotSupport::sendTo (int socket, const void *message, size_t length, int fl
|
|||
return send ({ packet, length });
|
||||
}
|
||||
|
||||
StringRef BotSupport::weaponIdToAlias (int32 id) {
|
||||
StringRef BotSupport::weaponIdToAlias (int32_t id) {
|
||||
StringRef none = "none";
|
||||
|
||||
if (m_weaponAlias.has (id)) {
|
||||
|
|
|
|||
|
|
@ -52,12 +52,16 @@
|
|||
<ClInclude Include="..\inc\message.h" />
|
||||
<ClInclude Include="..\inc\module.h" />
|
||||
<ClInclude Include="..\inc\product.h" />
|
||||
<ClInclude Include="..\inc\sounds.h" />
|
||||
<ClInclude Include="..\inc\support.h" />
|
||||
<ClInclude Include="..\inc\yapb.h" />
|
||||
<ClInclude Include="..\inc\version.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\src\entities.cpp" />
|
||||
<ClCompile Include="..\src\entities.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\botlib.cpp" />
|
||||
<ClCompile Include="..\src\chatlib.cpp" />
|
||||
<ClCompile Include="..\src\combat.cpp" />
|
||||
|
|
@ -70,6 +74,7 @@
|
|||
<ClCompile Include="..\src\message.cpp" />
|
||||
<ClCompile Include="..\src\module.cpp" />
|
||||
<ClCompile Include="..\src\navigate.cpp" />
|
||||
<ClCompile Include="..\src\sounds.cpp" />
|
||||
<ClCompile Include="..\src\support.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
|
@ -90,7 +95,7 @@
|
|||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<PlatformToolset>ClangCL</PlatformToolset>
|
||||
<UseOfMfc>false</UseOfMfc>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<EnableASAN>false</EnableASAN>
|
||||
|
|
@ -98,7 +103,7 @@
|
|||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseOfMfc>false</UseOfMfc>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<PlatformToolset>ClangCL</PlatformToolset>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<EnableASAN>false</EnableASAN>
|
||||
</PropertyGroup>
|
||||
|
|
|
|||
|
|
@ -153,6 +153,9 @@
|
|||
<ClInclude Include="..\ext\crlib\crlib\simd.h">
|
||||
<Filter>inc\ext\crlib</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\inc\sounds.h">
|
||||
<Filter>inc</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\src\botlib.cpp">
|
||||
|
|
@ -197,6 +200,9 @@
|
|||
<ClCompile Include="..\src\entities.cpp">
|
||||
<Filter>src</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\sounds.cpp">
|
||||
<Filter>src</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="yapb.rc">
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue