From ea482c6046d578e97ac613d72e0ae5b1699454f3 Mon Sep 17 00:00:00 2001 From: caxanga334 <10157643+caxanga334@users.noreply.github.com> Date: Fri, 15 Oct 2021 14:06:00 -0300 Subject: [PATCH] Hostage Support Very basic support for hostage mode. #9 --- utils/RCBot2_meta/bot_css_bot.cpp | 168 ++++++++++++++++++++++++++++-- utils/RCBot2_meta/bot_css_bot.h | 2 + utils/RCBot2_meta/bot_css_mod.cpp | 100 +++++++++++++++++- utils/RCBot2_meta/bot_getprop.cpp | 3 + utils/RCBot2_meta/bot_getprop.h | 36 +++++++ utils/RCBot2_meta/bot_mods.h | 10 ++ utils/RCBot2_meta/bot_utility.cpp | 3 + utils/RCBot2_meta/bot_utility.h | 3 + 8 files changed, 313 insertions(+), 12 deletions(-) diff --git a/utils/RCBot2_meta/bot_css_bot.cpp b/utils/RCBot2_meta/bot_css_bot.cpp index 5092e7a8..3e30b6e5 100644 --- a/utils/RCBot2_meta/bot_css_bot.cpp +++ b/utils/RCBot2_meta/bot_css_bot.cpp @@ -56,6 +56,8 @@ #include "rcbot/logging.h" +extern IServerGameEnts *servergameents; // for accessing the server game entities + void CCSSBot::init(bool bVarInit) { CBot::init();// require this @@ -577,6 +579,14 @@ void CCSSBot::modThink() } } + if(onLadder()) + { + setMoveLookPriority(MOVELOOK_OVERRIDE); + setLookAtTask(LOOK_WAYPOINT); + m_pButtons->holdButton(IN_FORWARD,0,1,0); + setMoveLookPriority(MOVELOOK_MODTHINK); + } + // Team Specific thinking switch (team) { @@ -596,6 +606,19 @@ void CCSSBot::modThink() { modThinkSlow(); } + + if(getEnemy() != NULL && isVisible(getEnemy())) + { + CBotWeapon *currentweapon = getCurrentWeapon(); + + if(!hasSomeConditions(CONDITION_OUT_OF_AMMO)) + { + if(currentweapon && !currentweapon->isMelee()) + { + stopMoving(); + } + } + } } void CCSSBot::modThinkSlow() @@ -642,6 +665,11 @@ void CCSSBot::getTasks(unsigned int iIgnore) ADD_UTILITY(BOT_UTIL_SEARCH_FOR_BOMB, !CCounterStrikeSourceMod::wasBombFound() && CCounterStrikeSourceMod::isBombPlanted(), 0.81f); ADD_UTILITY(BOT_UTIL_DEFUSE_BOMB, CCounterStrikeSourceMod::wasBombFound(), 0.85f); } + else if(CCounterStrikeSourceMod::isMapType(CS_MAP_HOSTAGERESCUE)) + { + ADD_UTILITY(BOT_UTIL_GET_HOSTAGE, CCounterStrikeSourceMod::canRescueHostages(), 0.85f); + ADD_UTILITY(BOT_UTIL_RESCUE, IsLeadingHostage(), 0.84f); + } break; } case CS_TEAM_TERRORIST: // TR specific utilities @@ -659,13 +687,13 @@ void CCSSBot::getTasks(unsigned int iIgnore) ADD_UTILITY(BOT_UTIL_SNIPE, IsSniper(), randomFloat(0.7900f, 0.8200f)); // Combat Utilities - ADD_UTILITY(BOT_UTIL_ENGAGE_ENEMY, hasSomeConditions(CONDITION_SEE_CUR_ENEMY) && !hasSomeConditions(CONDITION_OUT_OF_AMMO), 0.98f); + ADD_UTILITY(BOT_UTIL_ENGAGE_ENEMY, hasSomeConditions(CONDITION_SEE_CUR_ENEMY) && !hasSomeConditions(CONDITION_OUT_OF_AMMO), 1.00f); ADD_UTILITY(BOT_UTIL_WAIT_LAST_ENEMY, hasSomeConditions(CONDITION_ENEMY_OBSCURED), 0.95f); ADD_UTILITY(BOT_UTIL_HIDE_FROM_ENEMY, hasSomeConditions(CONDITION_SEE_CUR_ENEMY) && hasSomeConditions(CONDITION_OUT_OF_AMMO), 0.98f); // Generic Utilities ADD_UTILITY(BOT_UTIL_BUY, m_pBuyManager->wantsToBuy(), 1.0f); // Buy weapons - ADD_UTILITY(BOT_UTIL_ROAM, true, 0.0001f); // Roam around + ADD_UTILITY(BOT_UTIL_ROAM, true, 0.001f); // Roam around utils.execute(); @@ -688,13 +716,17 @@ void CCSSBot::getTasks(unsigned int iIgnore) if(m_fUtilTimes[next->getId()] < engine->Time()) m_fUtilTimes[next->getId()] = engine->Time() + randomFloat(0.1f, 2.0f); // saves problems with consistent failing - if(CClients::clientsDebugging(BOT_DEBUG_UTIL)) + if ( CClients::clientsDebugging(BOT_DEBUG_UTIL) ) { - char buffer[128]; - sprintf(buffer, "(%.4f) %s\nTeam: %i\nBomb Carrier: %s\nBomb Dropped: %s\nBomb Planted: %s", engine->Time(), g_szUtils[next->getId()], team, - CCounterStrikeSourceMod::isBombCarrier(this) ? "Yes" : "No", CCounterStrikeSourceMod::isBombDropped() ? "Yes" : "No", - CCounterStrikeSourceMod::isBombPlanted() ? "Yes" : "No"); - CClients::clientDebugMsg(BOT_DEBUG_UTIL, buffer, this); + int i = 0; + CClients::clientDebugMsg(this,BOT_DEBUG_UTIL,"-------- getTasks(%s) --------",m_szBotName); + + do + { + CClients::clientDebugMsg(this,BOT_DEBUG_UTIL,"%s = %0.3f",g_szUtils[next->getId()],next->getUtility(),this); + }while ((++i<20) && ((next = utils.nextBest()) != NULL)); + + CClients::clientDebugMsg(this,BOT_DEBUG_UTIL,"----END---- getTasks(%s) ----END----",m_szBotName); } break; } @@ -876,6 +908,67 @@ bool CCSSBot::executeAction(eBotAction iAction) } break; } + case BOT_UTIL_GET_HOSTAGE: + { + // Select a random hostage to rescue + CWaypoint* pWaypoint = NULL; + CWaypoint* pRoute = NULL; + CBotSchedule* pSched = new CBotSchedule(); + edict_t* pHostage = CCounterStrikeSourceMod::getRandomHostage(); + pSched->setID(SCHED_GOTONEST); + + if(CBotGlobals::entityIsAlive(pHostage)) + { + Vector vHostage = CBotGlobals::entityOrigin(pHostage); + pRoute = CWaypoints::randomRouteWaypoint(this, getOrigin(), vHostage, getTeam(), 0); + if((m_fUseRouteTime <= engine->Time())) + { + if(pRoute) + { + int iRoute = CWaypoints::getWaypointIndex(pRoute); // Route waypoint + pSched->addTask(new CFindPathTask(iRoute, LOOK_WAYPOINT)); + m_fUseRouteTime = engine->Time() + 30.0f; + } + } + + pSched->addTask(new CFindPathTask(pHostage)); + pSched->addTask(new CMoveToTask(pHostage)); + pSched->addTask(new CBotHL2DMUseButton(pHostage)); + pSched->addTask(new CBotWaitTask(1.0f)); + m_pSchedules->add(pSched); + } + + break; + } + case BOT_UTIL_RESCUE: + { + // Go to a random Rescue Zone waypoint + CWaypoint* pWaypoint = NULL; + CWaypoint* pRoute = NULL; + CBotSchedule* pSched = new CBotSchedule(); + pSched->setID(SCHED_GOTO_ORIGIN); + + pWaypoint = CWaypoints::randomWaypointGoal(CWaypointTypes::W_FL_RESCUEZONE, getTeam(), 0, false, this, false); + + if(pWaypoint) + { + pRoute = CWaypoints::randomRouteWaypoint(this, getOrigin(), pWaypoint->getOrigin(), getTeam(), pWaypoint->getArea()); + if((m_fUseRouteTime <= engine->Time())) + { + if(pRoute) + { + int iRoute = CWaypoints::getWaypointIndex(pRoute); // Route waypoint + pSched->addTask(new CFindPathTask(iRoute, LOOK_WAYPOINT)); + m_fUseRouteTime = engine->Time() + 30.0f; + } + } + + pSched->addTask(new CFindPathTask(CWaypoints::getWaypointIndex(pWaypoint))); + pSched->addTask(new CBotWaitTask(3.0f)); + m_pSchedules->add(pSched); + } + break; + } case BOT_UTIL_SNIPE: { CWaypoint *pWaypoint = NULL; @@ -886,7 +979,7 @@ bool CCSSBot::executeAction(eBotAction iAction) if(pWaypoint) { CFindPathTask *pFindPath = new CFindPathTask(CWaypoints::getWaypointIndex(pWaypoint)); - pFindPath->setInterruptFunction(new CBotCSSRoamInterrupt()); + //pFindPath->setInterruptFunction(new CBotCSSRoamInterrupt()); CCSSGuardTask *pGuard = new CCSSGuardTask(getPrimaryWeapon(), pWaypoint->getOrigin(), pWaypoint->getAimYaw(), false, 0.0f, pWaypoint->getFlags()); pSched->addTask(pFindPath); pSched->addTask(pGuard); @@ -908,7 +1001,7 @@ bool CCSSBot::executeAction(eBotAction iAction) { int iWaypoint = CWaypoints::getWaypointIndex(pWaypoint); CFindPathTask *pFindPath = new CFindPathTask(iWaypoint); - pFindPath->setInterruptFunction(new CBotCSSRoamInterrupt()); + //pFindPath->setInterruptFunction(new CBotCSSRoamInterrupt()); pSched->addTask(pFindPath); m_pSchedules->add(pSched); @@ -925,4 +1018,59 @@ bool CCSSBot::executeAction(eBotAction iAction) void CCSSBot::onRoundStart() { m_pBuyManager->onRoundStart(); +} + +bool CCSSBot::IsLeadingHostage() +{ + std::vector hostages = CCounterStrikeSourceMod::getHostageVector(); + edict_t *pHostage = NULL; + + if(getTeam() != CS_TEAM_COUNTERTERRORIST) + return false; + + if(hostages.size() == 0) + return false; + + for(CBaseHandle i : hostages) + { + edict_t *pHostage = INDEXENT(i.GetEntryIndex()); + + if(CBotGlobals::entityIsValid(pHostage) && CClassInterface::getCSHostageLeader(pHostage) == m_pEdict) + { + return true; + } + } + + return false; +} + +void CCSSBot::touchedWpt(CWaypoint *pWaypoint, int iNextWaypoint, int iPrevWaypoint) +{ + if(iNextWaypoint != -1 && pWaypoint->hasFlag(CWaypointTypes::W_FL_DOOR)) // Use waypoint: Check for door + { + CWaypoint *pNext = CWaypoints::getWaypoint(iNextWaypoint); + if(pNext) + { + /** + * Traces a line between the current waypoint and the next waypoint. If a door is blocking the path, try to open it. + **/ + CTraceFilterHitAll filter; + trace_t *tr = CBotGlobals::getTraceResult(); + CBotGlobals::traceLine(pWaypoint->getOrigin() + Vector(0,0,CWaypoint::WAYPOINT_HEIGHT/2), pNext->getOrigin() + Vector(0,0,CWaypoint::WAYPOINT_HEIGHT/2), MASK_PLAYERSOLID, &filter); + if(tr->fraction < 1.0f) + { + if(tr->m_pEnt) + { + edict_t *pDoor = servergameents->BaseEntityToEdict(tr->m_pEnt); + const char *szclassname = pDoor->GetClassName(); + if(strncmp(szclassname, "prop_door_rotating", 18) == 0 || strncmp(szclassname, "func_door", 9) == 0 || strncmp(szclassname, "func_door_rotating", 18) == 0) + { + m_pSchedules->addFront(new CSynOpenDoorSched(pDoor)); + } + } + } + } + } + + CBot::touchedWpt(pWaypoint, iNextWaypoint, iPrevWaypoint); } \ No newline at end of file diff --git a/utils/RCBot2_meta/bot_css_bot.h b/utils/RCBot2_meta/bot_css_bot.h index 8f7db5c0..21096491 100644 --- a/utils/RCBot2_meta/bot_css_bot.h +++ b/utils/RCBot2_meta/bot_css_bot.h @@ -65,6 +65,7 @@ class CCSSBot : public CBot void modThink() override; void listenForPlayers() override; void freeMapMemory() override; + void touchedWpt(CWaypoint *pWaypoint, int iNextWaypoint = -1, int iPrevWaypoint = -1) override; virtual void modThinkSlow(); unsigned int maxEntityIndex() override { return gpGlobals->maxEntities; } void getTasks (unsigned int iIgnore=0) override; @@ -77,6 +78,7 @@ class CCSSBot : public CBot virtual CBotWeapon *getPrimaryWeapon(); virtual bool IsSniper(); virtual void onRoundStart(); + virtual bool IsLeadingHostage(); private: edict_t *m_pCurrentWeapon; // The bot current weapon float m_fNextAttackTime; // Control timer for bot primary attack diff --git a/utils/RCBot2_meta/bot_css_mod.cpp b/utils/RCBot2_meta/bot_css_mod.cpp index cc39ad59..650f5fbd 100644 --- a/utils/RCBot2_meta/bot_css_mod.cpp +++ b/utils/RCBot2_meta/bot_css_mod.cpp @@ -62,6 +62,7 @@ float CCounterStrikeSourceMod::m_fBombPlantedTime = 0.0f; bool CCounterStrikeSourceMod::m_bIsBombPlanted = false; bool CCounterStrikeSourceMod::m_bBombWasFound = false; CBaseHandle CCounterStrikeSourceMod::m_hBomb = NULL; +std::vector CCounterStrikeSourceMod::m_hHostages; void CCounterStrikeSourceMod::initMod() @@ -184,6 +185,11 @@ void CCounterStrikeSourceMod::onRoundStart() pCSBot->onRoundStart(); } } + + if(CCounterStrikeSourceMod::isMapType(CS_MAP_HOSTAGERESCUE)) + { + updateHostages(); + } } /** @@ -198,7 +204,6 @@ void CCounterStrikeSourceMod::onFreezeTimeEnd() if(pC4) { m_hBomb.Init(engine->IndexOfEdict(pC4), pC4->m_NetworkSerialNumber); - logger->Log(LogLevel::DEBUG, "CSS C4: %i %i %s", m_hBomb.GetEntryIndex(), m_hBomb.GetSerialNumber(), m_hBomb.IsValid() ? "Valid" : "Invalid"); } for(short int i = 0; i < MAX_PLAYERS; i++) @@ -226,7 +231,6 @@ void CCounterStrikeSourceMod::onBombPlanted() if(pPlantedC4) { m_hBomb.Init(engine->IndexOfEdict(pPlantedC4), pPlantedC4->m_NetworkSerialNumber); - logger->Log(LogLevel::DEBUG, "CSS C4: %i %i %s", m_hBomb.GetEntryIndex(), m_hBomb.GetSerialNumber(), m_hBomb.IsValid() ? "Valid" : "Invalid"); } for(short int i = 0; i < MAX_PLAYERS; i++) @@ -241,4 +245,96 @@ void CCounterStrikeSourceMod::onBombPlanted() } } } +} + +/** + * Hostage entities needs to be updated on round start since killed hostages gets their entity deleted. + **/ +void CCounterStrikeSourceMod::updateHostages() +{ + edict_t *current; + CBaseHandle bh; + m_hHostages.clear(); + + for(int i = gpGlobals->maxClients + 1; i < gpGlobals->maxEntities; i++) + { + bh.Term(); + current = engine->PEntityOfEntIndex(i); + if (current == NULL) + { + continue; + } + + IServerNetworkable *network = current->GetNetworkable(); + if (network == NULL) + { + continue; + } + + //const char *classname = current->GetClassName(); + ServerClass *sClass = network->GetServerClass(); + const char *sname = sClass->GetName(); + + if(strcmp(sname, "CHostage") == 0) + { + bh.Init(i, current->m_NetworkSerialNumber); + m_hHostages.push_back(bh); + } + } + + logger->Log(LogLevel::DEBUG, "Hostage Vector Size %i", m_hHostages.size()); + + for(CBaseHandle i : m_hHostages) + { + logger->Log(LogLevel::DEBUG, "Stored Hostage: %i - %i", i.GetEntryIndex(), i.GetSerialNumber()); + } +} + +/** + * Checks if there are hostages that can be rescued + **/ +bool CCounterStrikeSourceMod::canRescueHostages() +{ + if(m_hHostages.size() == 0) + return false; + + edict_t *pHostage; + + for(CBaseHandle i : m_hHostages) + { + pHostage = INDEXENT(i.GetEntryIndex()); + + if(CBotGlobals::entityIsValid(pHostage) && !CClassInterface::isCSHostageRescued(pHostage) && CClassInterface::getCSHostageLeader(pHostage) == NULL) + { + return true; + } + } + + return false; +} + +edict_t *CCounterStrikeSourceMod::getRandomHostage() +{ + std::vector temp; + edict_t *pEdict; + + // Build a new vector with hostages that are valid to be rescued + for(CBaseHandle i : temp) + { + pEdict = INDEXENT(i.GetEntryIndex()); + + if(CBotGlobals::entityIsValid(pEdict) && !CClassInterface::isCSHostageRescued(pEdict) && CClassInterface::getCSHostageLeader(pEdict) == NULL && CClassInterface::getCSHostageHealth(pEdict) > 0) + { + temp.push_back(i); + } + } + + if(temp.size() > 0) + { + return INDEXENT(temp.at(randomInt(0, temp.size() - 1)).GetEntryIndex()); + } + else + { + return NULL; + } } \ No newline at end of file diff --git a/utils/RCBot2_meta/bot_getprop.cpp b/utils/RCBot2_meta/bot_getprop.cpp index d3974a6d..b68d859e 100644 --- a/utils/RCBot2_meta/bot_getprop.cpp +++ b/utils/RCBot2_meta/bot_getprop.cpp @@ -577,6 +577,9 @@ void CClassInterface:: init () DEFINE_GETPROP(GETPROP_CSS_HASDEFUSER, "CCSPlayer", "m_bHasDefuser", 0); DEFINE_GETPROP(GETPROP_CSS_HASHELMET, "CCSPlayer", "m_bHasHelmet", 0); DEFINE_GETPROP(GETPROP_CSS_BOMBTICKING, "CPlantedC4", "m_bBombTicking", 0); + DEFINE_GETPROP(GETPROP_CSS_HOSTAGE_HEALTH, "CHostage", "m_iHealth", 0); + DEFINE_GETPROP(GETPROP_CSS_HOSTAGE_RESCUED, "CHostage", "m_isRescued", 0); + DEFINE_GETPROP(GETPROP_CSS_HOSTAGE_LEADER, "CHostage", "m_leader", 0); // Generic DEFINE_GETPROP(GETPROP_PLAYER_FOV, "CBasePlayer", "m_iFOV", 0); diff --git a/utils/RCBot2_meta/bot_getprop.h b/utils/RCBot2_meta/bot_getprop.h index 8ab969de..31b7ee8a 100644 --- a/utils/RCBot2_meta/bot_getprop.h +++ b/utils/RCBot2_meta/bot_getprop.h @@ -163,6 +163,9 @@ typedef enum GETPROP_CSS_BOMBTICKING, GETPROP_PLAYER_FOV, GETPROP_PLAYER_LIFESTATE, + GETPROP_CSS_HOSTAGE_HEALTH, + GETPROP_CSS_HOSTAGE_RESCUED, + GETPROP_CSS_HOSTAGE_LEADER, GET_PROPDATA_MAX }getpropdata_id; @@ -836,6 +839,39 @@ class CClassInterface return g_GetProps[GETPROP_CSS_BOMBTICKING].getBool(pBomb, false); } + /** + * Checks how much health a specific hostage has + * + * @param pHostage The hostage entity edict + * @return How much health the given hostage has + **/ + inline static int getCSHostageHealth(edict_t* pHostage) + { + return g_GetProps[GETPROP_CSS_HOSTAGE_HEALTH].getInt(pHostage, 0); + } + + /** + * Checks if the specified hostage has been rescued + * + * @param pHostage The hostage entity edict + * @return TRUE if the given hostage has been rescued + **/ + inline static bool isCSHostageRescued(edict_t* pHostage) + { + return g_GetProps[GETPROP_CSS_HOSTAGE_RESCUED].getBool(pHostage, false); + } + + /** + * Gets the edict of the player currently leading the hostage + * + * @param pHostage The hostage entity edict + * @return Edict pointer of the player leading the hostage + **/ + inline static edict_t* getCSHostageLeader(edict_t* pHostage) + { + return g_GetProps[GETPROP_CSS_HOSTAGE_LEADER].getEntity(pHostage); + } + private: static CClassInterfaceValue g_GetProps[GET_PROPDATA_MAX]; diff --git a/utils/RCBot2_meta/bot_mods.h b/utils/RCBot2_meta/bot_mods.h index 4fec32b7..222dbc7e 100644 --- a/utils/RCBot2_meta/bot_mods.h +++ b/utils/RCBot2_meta/bot_mods.h @@ -674,14 +674,24 @@ class CCounterStrikeSourceMod : public CBotMod } static bool canHearPlantedBomb(CBot *pBot); static bool isScoped(CBot *pBot); + static void updateHostages(); + static edict_t *getRandomHostage(); + static bool canRescueHostages(); + inline static std::vector getHostageVector() + { + return m_hHostages; + } //void entitySpawn ( edict_t *pEntity ); + private: + static eCSSMapType m_MapType; // Map Type static float m_fRoundStartTime; // The time when the round started static float m_fBombPlantedTime; // The time when the bomb was planted static bool m_bIsBombPlanted; // Is the bomb planted? static bool m_bBombWasFound; // Did the CTs locate the bomb? static CBaseHandle m_hBomb; // The bomb. Experimental CBaseHandle instead of MyEHandle + static std::vector m_hHostages; // Vector with hostage handles }; class CTimCoopMod : public CBotMod diff --git a/utils/RCBot2_meta/bot_utility.cpp b/utils/RCBot2_meta/bot_utility.cpp index 763987b4..e77c111a 100644 --- a/utils/RCBot2_meta/bot_utility.cpp +++ b/utils/RCBot2_meta/bot_utility.cpp @@ -150,6 +150,9 @@ const char *g_szUtils[BOT_UTIL_MAX+1] = "BOT_UTIL_WAIT_LAST_ENEMY", "BOT_UTIL_ENGAGE_ENEMY", "BOT_UTIL_SEARCH_FOR_BOMB", + "BOT_UTIL_RESCUE", + "BOT_UTIL_GUARD_RESCUE_ZONE", + "BOT_UTIL_GET_HOSTAGE", "BOT_UTIL_MAX" }; diff --git a/utils/RCBot2_meta/bot_utility.h b/utils/RCBot2_meta/bot_utility.h index 184bd9fd..d2c66845 100644 --- a/utils/RCBot2_meta/bot_utility.h +++ b/utils/RCBot2_meta/bot_utility.h @@ -150,6 +150,9 @@ typedef enum BOT_UTIL_WAIT_LAST_ENEMY, BOT_UTIL_ENGAGE_ENEMY, BOT_UTIL_SEARCH_FOR_BOMB, + BOT_UTIL_RESCUE, + BOT_UTIL_GUARD_RESCUE_ZONE, + BOT_UTIL_GET_HOSTAGE, BOT_UTIL_MAX }eBotAction;