bot: add more support for zombie mod scenario (ref #563)

added multiple items to custom.cfg, so game delay timer cvar is now configurable, the infected team is configurable as well.

creature (well, just zombies) now correctly detects their "creature" status even with custom model names (assumes that bot is on an infected team = zombie)

Co-Authored-By: Max <161382234+dyspose@users.noreply.github.com>
This commit is contained in:
jeefo 2024-05-15 22:56:35 +03:00
commit dedbf8ab82
No known key found for this signature in database
GPG key ID: D696786B81B667C8
8 changed files with 91 additions and 14 deletions

View file

@ -6,6 +6,8 @@
;
; Custom configuration file, allow to change some hardcoded stuff in bot code.
;
; NOTE: All changes to this file takes effect only on server restart.
;
;
; Custom name for C4 model, for servers that replacing C4 model with it's own.
@ -28,3 +30,23 @@ AMXParachuteCvar = sv_parachute
;
CustomCSDMSpawnPoint = view_spawn
;
; Primary cvar for detection if CSDM mod is activated in game.
;
CSDMDetectCvar = csdm_active
;
; Primary cvar to detect if bot is running on Zombie Mod.
;
ZMDetectCvar = zp_delay
;
; For Zombie Mod, the cvars that deals with time before any game mode starts.
;
ZMDelayCvar = zp_delay
;
; For Zombie Mod, determines the team on which infected players are on.
; Valid values: T, CT.
;
ZMInfectedTeam = T

View file

@ -47,7 +47,8 @@ CR_DECLARE_SCOPED_ENUM (GameFlags,
HasFakePings = cr::bit (10), // on that game version we can fake bots pings
HasBotVoice = cr::bit (11), // on that game version we can use chatter
AnniversaryHL25 = cr::bit (12), // half-life 25th anniversary engine
Xash3DLegacy = cr::bit (13) // old xash3d-branch
Xash3DLegacy = cr::bit (13), // old xash3d-branch
ZombieMod = cr::bit (14) // zombie mod is active
)
// defines map type

View file

@ -122,6 +122,7 @@ public:
void setLastWinner (int winner);
void checkBotModel (edict_t *ent, char *infobuffer);
void checkNeedsToBeKicked ();
void refreshCreatureStatus ();
bool isTeamStacked (int team);
bool kickRandom (bool decQuota = true, Team fromTeam = Team::Unassigned);

View file

@ -306,6 +306,7 @@ private:
bool m_moveToC4 {}; // ct is moving to bomb
bool m_needToSendWelcomeChat {}; // bot needs to greet people on server?
bool m_isCreature {}; // bot is not a player, but something else ? zombie ?
bool m_isOnInfectedTeam {}; // bot is zombie (this assumes bot is a creature)
bool m_defuseNotified {}; // bot is notified about bomb defusion
bool m_jumpSequence {}; // next path link will be jump link
bool m_checkFall {}; // check bot fall
@ -500,7 +501,7 @@ private:
void selectWeaponByIndex (int index);
void syncUpdatePredictedIndex ();
void updatePredictedIndex ();
void refreshModelName (char *infobuffer);
void refreshCreatureStatus (char *infobuffer);
void updateRightRef ();
void completeTask ();

View file

@ -3244,7 +3244,7 @@ void Bot::logic () {
}
void Bot::spawned () {
if (game.is (GameFlags::CSDM)) {
if (game.is (GameFlags::CSDM | GameFlags::ZombieMod)) {
newRound ();
clearTasks ();
}
@ -4089,7 +4089,27 @@ float Bot::getShiftSpeed () {
return pev->maxspeed * 0.4f;
}
void Bot::refreshModelName (char *infobuffer) {
void Bot::refreshCreatureStatus (char *infobuffer) {
// if bot is on infected team, assume he is a creature
if (game.is (GameFlags::ZombieMod)) {
static StringRef zmInfectedTeam (conf.fetchCustom ("ZMInfectedTeam"));
// by default infected team is terrorists
Team infectedTeam = Team::Terrorist;
if (zmInfectedTeam == "CT") {
infectedTeam = Team::CT;
}
// if bot is on infected team, and zombie mode is active, assume bot is a creature/zombie
m_isOnInfectedTeam = game.getRealTeam (ent ()) == infectedTeam;
// do not process next if already infected
if (m_isOnInfectedTeam) {
return;
}
}
if (infobuffer == nullptr) {
infobuffer = engfuncs.pfnGetInfoKeyBuffer (ent ());
}
@ -4115,5 +4135,5 @@ bool Bot::isCreature () {
constexpr auto modelMaskZombie = (('o' << 8) + 'z');
constexpr auto modelMaskChicken = (('h' << 8) + 'c');
return m_modelMask == modelMaskZombie || m_modelMask == modelMaskChicken;
return m_isOnInfectedTeam || m_modelMask == modelMaskZombie || m_modelMask == modelMaskChicken;
}

View file

@ -661,6 +661,10 @@ void BotConfig::loadCustomConfig () {
m_custom["C4ModelName"] = "c4.mdl";
m_custom["AMXParachuteCvar"] = "sv_parachute";
m_custom["CustomCSDMSpawnPoint"] = "view_spawn";
m_custom["CSDMDetectCvar"] = "csdm_active";
m_custom["ZMDetectCvar"] = "zp_delay";
m_custom["ZMDelayCvar"] = "zp_delay";
m_custom["ZMInfectedTeam"] = "T";
};
setDefaults ();

View file

@ -951,7 +951,11 @@ void Game::applyGameModes () {
return;
}
static ConVarRef csdm_active ("csdm_active");
static StringRef csdmActiveCvarName = conf.fetchCustom ("CSDMDetectCvar");
static StringRef zmActiveCvarName = conf.fetchCustom ("ZMDetectCvar");
static StringRef zmDelayCvarName = conf.fetchCustom ("ZMDelayCvar");
static ConVarRef csdm_active (csdmActiveCvarName);
static ConVarRef csdm_version ("csdm_version");
static ConVarRef redm_active ("redm_active");
static ConVarRef mp_freeforall ("mp_freeforall");
@ -976,12 +980,21 @@ void Game::applyGameModes () {
}
}
// some little support for zombie plague
static ConVarRef zp_delay ("zp_delay");
// does zombie mod is in use
static ConVarRef zm_active (zmActiveCvarName);
// update our ignore timer if zp_elay exists
if (zp_delay.exists () && zp_delay.value () > 0.0f) {
cv_ignore_enemies_after_spawn_time.set (zp_delay.value () + 3.0f);
// do a some little support for zombie plague
if (zm_active.exists ()) {
static ConVarRef zm_delay (zmDelayCvarName);
// update our ignore timer if zp_delay exists
if (zm_delay.exists () && zm_delay.value () > 0.0f) {
cv_ignore_enemies_after_spawn_time.set (zm_delay.value () + 3.5f);
}
m_gameFlags |= GameFlags::ZombieMod;
}
else {
m_gameFlags &= ~GameFlags::ZombieMod;
}
}
@ -1033,6 +1046,9 @@ void Game::slowFrame () {
// kick failed bots
bots.checkNeedsToBeKicked ();
// refresh bot infection (creature) status
bots.refreshCreatureStatus ();
// update next update time
m_oneSecondFrame = nextUpdate + time ();
}

View file

@ -814,7 +814,7 @@ void BotManager::setLastWinner (int winner) {
void BotManager::checkBotModel (edict_t *ent, char *infobuffer) {
for (const auto &bot : bots) {
if (bot->ent () == ent) {
bot->refreshModelName (infobuffer);
bot->refreshCreatureStatus (infobuffer);
break;
}
}
@ -829,6 +829,18 @@ void BotManager::checkNeedsToBeKicked () {
}
}
void BotManager::refreshCreatureStatus () {
if (!game.is (GameFlags::ZombieMod)) {
return;
}
for (const auto &bot : bots) {
if (bot->m_isAlive) {
bot->refreshCreatureStatus (nullptr);
}
}
}
void BotManager::setWeaponMode (int selection) {
// this function sets bots weapon mode
@ -1370,7 +1382,7 @@ void BotManager::handleDeath (edict_t *killer, edict_t *victim) {
}
}
// mark bot as "spawned", and reset it to new-round state when it dead (for csdm only)
// mark bot as "spawned", and reset it to new-round state when it dead (for csdm/zombie only)
if (victimBot != nullptr) {
victimBot->spawned ();
}
@ -1519,7 +1531,7 @@ void Bot::newRound () {
for (auto &timer : m_chatterTimes) {
timer = kMaxChatterRepeatInterval;
}
refreshModelName (nullptr);
refreshCreatureStatus (nullptr);
m_isReloading = false;
m_reloadState = Reload::None;