diff --git a/main/source/detour/Include/DetourTileCache.h b/main/source/detour/Include/DetourTileCache.h index 927af7b3..942c913f 100644 --- a/main/source/detour/Include/DetourTileCache.h +++ b/main/source/detour/Include/DetourTileCache.h @@ -300,14 +300,14 @@ private: dtOffMeshConnection* m_offMeshConnections; dtOffMeshConnection* m_nextFreeOffMeshConnection; - static const int MAX_REQUESTS = 256; + static const int MAX_REQUESTS = 512; ObstacleRequest m_reqs[MAX_REQUESTS]; int m_nreqs; OffMeshRequest m_OffMeshReqs[MAX_REQUESTS]; int m_nOffMeshReqs; - static const int MAX_UPDATE = 256; + static const int MAX_UPDATE = 512; dtCompressedTileRef m_update[MAX_UPDATE]; int m_nupdate; }; diff --git a/main/source/dlls/client.cpp b/main/source/dlls/client.cpp index 225c8237..b70a7061 100644 --- a/main/source/dlls/client.cpp +++ b/main/source/dlls/client.cpp @@ -145,6 +145,7 @@ #include "../mod/AvHAlienAbilityConstants.h" #include "../mod/AvHNetworkMessages.h" #include "../mod/AvHNexusServer.h" +#include "../mod/AIPlayers/AvHAIPlayerManager.h" #include "../game_shared/voice_gamemgr.h" extern CVoiceGameMgr g_VoiceGameMgr; @@ -394,10 +395,14 @@ void Host_Say( edict_t *pEntity, int teamonly ) if ( !stricmp( pcmd, cpSay) || !stricmp( pcmd, cpSayTeam ) ) { - if ( CMD_ARGC() >= 2 ) + int NumArgs = CMD_ARGC(); + + if (NumArgs >= 2 ) { p = (char *)CMD_ARGS(); + bool bMessageParsed = false; + if(GetGameRules()->GetIsTournamentMode() && !GetGameRules()->GetGameStarted()) { if(!strcmp(CMD_ARGV(1), kReadyNotification)) @@ -408,6 +413,8 @@ void Host_Say( edict_t *pEntity, int teamonly ) { theTeam->SetIsReady(); } + + bMessageParsed = true; } else if (!strcmp(CMD_ARGV(1), kNotReadyNotification)) { @@ -417,8 +424,33 @@ void Host_Say( edict_t *pEntity, int teamonly ) { theTeam->SetIsReady(false); } + + bMessageParsed = true; } } + + // Check to see if we are asking the AI commander for something + if (!bMessageParsed) + { + char shortenedMsg[32]; + char* msg = (char*)CMD_ARGV(1); + + strncpy(shortenedMsg, msg, 31); + + char* pch; + pch = strtok(shortenedMsg, " "); + + if (!stricmp(pch, kAICommanderRequest)) + { + pch = strtok(NULL, " \n"); + + if (pch != NULL) + { + AIMGR_ReceiveCommanderRequest((AvHTeamNumber)pEntity->v.team, pEntity, pch); + } + } + + } } else { diff --git a/main/source/mod/AIPlayers/AvHAICommander.cpp b/main/source/mod/AIPlayers/AvHAICommander.cpp index 70bc7029..a34a6581 100644 --- a/main/source/mod/AIPlayers/AvHAICommander.cpp +++ b/main/source/mod/AIPlayers/AvHAICommander.cpp @@ -868,10 +868,50 @@ bool AICOMM_IsRequestValid(ai_commander_request* Request) { if (Request->bResponded) { return false; } + // We tried and failed to respond 5 times, give up so we don't block the queue of people needing help + if (Request->ResponseAttempts > 5) { return false; } + + edict_t* Requestor = Request->Requestor; + + if (FNullEnt(Requestor) || !IsPlayerActiveInGame(Requestor)) { return false; } + + AvHPlayer* PlayerRef = dynamic_cast(CBaseEntity::Instance(Requestor)); + + if (!PlayerRef) { return false; } + + AvHTeamNumber RequestorTeam = PlayerRef->GetTeam(); + switch (Request->RequestType) { case COMMANDER_NEXTHEALTH: - return Request->Requestor->v.health < Request->Requestor->v.max_health; + return Requestor->v.health < Requestor->v.max_health; + case BUILD_SHOTGUN: + return !PlayerHasWeapon(PlayerRef, WEAPON_MARINE_SHOTGUN) + && !AITAC_ItemExistsInLocation(Requestor->v.origin, DEPLOYABLE_ITEM_SHOTGUN, RequestorTeam, AI_REACHABILITY_MARINE, 0.0f, UTIL_MetresToGoldSrcUnits(5.0f), false) + && AITAC_IsCompletedStructureOfTypeNearLocation(RequestorTeam, (STRUCTURE_MARINE_ARMOURY | STRUCTURE_MARINE_ADVARMOURY), Requestor->v.origin, UTIL_MetresToGoldSrcUnits(5.0f)) ; + case BUILD_WELDER: + return !PlayerHasWeapon(PlayerRef, WEAPON_MARINE_WELDER) + && !AITAC_ItemExistsInLocation(Requestor->v.origin, DEPLOYABLE_ITEM_WELDER, RequestorTeam, AI_REACHABILITY_MARINE, 0.0f, UTIL_MetresToGoldSrcUnits(5.0f), false) + && AITAC_IsCompletedStructureOfTypeNearLocation(RequestorTeam, (STRUCTURE_MARINE_ARMOURY | STRUCTURE_MARINE_ADVARMOURY), Requestor->v.origin, UTIL_MetresToGoldSrcUnits(5.0f)); + case BUILD_HMG: + return !PlayerHasWeapon(PlayerRef, WEAPON_MARINE_HMG) + && !AITAC_ItemExistsInLocation(Requestor->v.origin, DEPLOYABLE_ITEM_HMG, RequestorTeam, AI_REACHABILITY_MARINE, 0.0f, UTIL_MetresToGoldSrcUnits(5.0f), false) + && AITAC_IsCompletedStructureOfTypeNearLocation(RequestorTeam, STRUCTURE_MARINE_ADVARMOURY, Requestor->v.origin, UTIL_MetresToGoldSrcUnits(5.0f)); + case BUILD_MINES: + return !PlayerHasWeapon(PlayerRef, WEAPON_MARINE_MINES) + && !AITAC_ItemExistsInLocation(Requestor->v.origin, DEPLOYABLE_ITEM_MINES, RequestorTeam, AI_REACHABILITY_MARINE, 0.0f, UTIL_MetresToGoldSrcUnits(5.0f), false) + && AITAC_IsCompletedStructureOfTypeNearLocation(RequestorTeam, (STRUCTURE_MARINE_ARMOURY | STRUCTURE_MARINE_ADVARMOURY), Requestor->v.origin, UTIL_MetresToGoldSrcUnits(5.0f)); + case BUILD_CAT: + return !IsPlayerBuffed(Requestor) + && !AITAC_ItemExistsInLocation(Requestor->v.origin, DEPLOYABLE_ITEM_CATALYSTS, RequestorTeam, AI_REACHABILITY_MARINE, 0.0f, UTIL_MetresToGoldSrcUnits(5.0f), false) + && AITAC_IsCompletedStructureOfTypeNearLocation(RequestorTeam, (STRUCTURE_MARINE_ARMOURY | STRUCTURE_MARINE_ADVARMOURY), Requestor->v.origin, 0.0f) + && AITAC_ResearchIsComplete(RequestorTeam, TECH_RESEARCH_CATALYSTS); + case BUILD_PHASEGATE: + return !AITAC_IsStructureOfTypeNearLocation(RequestorTeam, STRUCTURE_MARINE_PHASEGATE, Requestor->v.origin, UTIL_MetresToGoldSrcUnits(5.0f)); + case BUILD_TURRET_FACTORY: + return !AITAC_IsStructureOfTypeNearLocation(RequestorTeam, (STRUCTURE_MARINE_TURRETFACTORY | STRUCTURE_MARINE_ADVTURRETFACTORY), Requestor->v.origin, UTIL_MetresToGoldSrcUnits(5.0f)); + case BUILD_ARMORY: + return !AITAC_IsStructureOfTypeNearLocation(RequestorTeam, (STRUCTURE_MARINE_ARMOURY | STRUCTURE_MARINE_ADVARMOURY), Requestor->v.origin, UTIL_MetresToGoldSrcUnits(5.0f)); default: return true; } @@ -2215,6 +2255,10 @@ bool AICOMM_CheckForNextSupportAction(AvHAIPlayer* pBot) NextRequest->bResponded = true; } } + else + { + NextRequest->ResponseAttempts++; + } return true; } @@ -2280,6 +2324,10 @@ bool AICOMM_CheckForNextSupportAction(AvHAIPlayer* pBot) NextRequest->bResponded = true; } } + else + { + NextRequest->ResponseAttempts++; + } return true; } @@ -2298,6 +2346,276 @@ bool AICOMM_CheckForNextSupportAction(AvHAIPlayer* pBot) NextRequest->bResponded = true; } + if (NextRequest->RequestType == BUILD_CAT) + { + Vector DeployLocation = UTIL_GetRandomPointOnNavmeshInRadius(GetBaseNavProfile(MARINE_BASE_NAV_PROFILE), Requestor->v.origin, UTIL_MetresToGoldSrcUnits(2.0f)); + bool bSuccess = AICOMM_DeployItem(pBot, DEPLOYABLE_ITEM_AMMO, DeployLocation); + + if (bSuccess) + { + NextRequest->bResponded = true; + } + else + { + NextRequest->ResponseAttempts++; + } + + return true; + } + + if (NextRequest->RequestType == BUILD_WELDER) + { + if (pBot->Player->GetResources() < BALANCE_VAR(kWelderCost)) { return false; } + + DeployableSearchFilter ArmouryFilter; + ArmouryFilter.DeployableTeam = CommanderTeam; + ArmouryFilter.DeployableTypes = (STRUCTURE_MARINE_ARMOURY | STRUCTURE_MARINE_ADVARMOURY); + ArmouryFilter.IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED; + ArmouryFilter.ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING; + + AvHAIBuildableStructure* NearestArmoury = AITAC_FindClosestDeployableToLocation(Requestor->v.origin, &ArmouryFilter); + + if (!NearestArmoury) + { + NextRequest->bResponded = true; + return false; + } + + Vector DeployLocation = UTIL_GetRandomPointOnNavmeshInRadius(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), NearestArmoury->Location, UTIL_MetresToGoldSrcUnits(4.0f)); + + if (vIsZero(DeployLocation)) + { + DeployLocation = UTIL_GetRandomPointOnNavmeshInRadius(GetBaseNavProfile(MARINE_BASE_NAV_PROFILE), NearestArmoury->Location, UTIL_MetresToGoldSrcUnits(4.0f)); + } + + if (vIsZero(DeployLocation)) + { + NextRequest->bResponded = true; + return false; + } + + bool bSuccess = AICOMM_DeployItem(pBot, DEPLOYABLE_ITEM_WELDER, DeployLocation); + + NextRequest->ResponseAttempts++; + + NextRequest->bResponded = bSuccess; + return true; + + } + + if (NextRequest->RequestType == BUILD_SHOTGUN) + { + if (pBot->Player->GetResources() < BALANCE_VAR(kShotgunCost)) { return false; } + + DeployableSearchFilter ArmouryFilter; + ArmouryFilter.DeployableTeam = CommanderTeam; + ArmouryFilter.DeployableTypes = (STRUCTURE_MARINE_ARMOURY | STRUCTURE_MARINE_ADVARMOURY); + ArmouryFilter.IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED; + ArmouryFilter.ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING; + + AvHAIBuildableStructure* NearestArmoury = AITAC_FindClosestDeployableToLocation(Requestor->v.origin, &ArmouryFilter); + + if (!NearestArmoury) + { + NextRequest->bResponded = true; + return false; + } + + Vector DeployLocation = UTIL_GetRandomPointOnNavmeshInRadius(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), NearestArmoury->Location, UTIL_MetresToGoldSrcUnits(4.0f)); + + if (vIsZero(DeployLocation)) + { + DeployLocation = UTIL_GetRandomPointOnNavmeshInRadius(GetBaseNavProfile(MARINE_BASE_NAV_PROFILE), NearestArmoury->Location, UTIL_MetresToGoldSrcUnits(4.0f)); + } + + if (vIsZero(DeployLocation)) + { + NextRequest->bResponded = true; + return false; + } + + bool bSuccess = AICOMM_DeployItem(pBot, DEPLOYABLE_ITEM_SHOTGUN, DeployLocation); + + NextRequest->ResponseAttempts++; + + NextRequest->bResponded = bSuccess; + return true; + + } + + if (NextRequest->RequestType == BUILD_MINES) + { + if (pBot->Player->GetResources() < BALANCE_VAR(kMineCost)) { return false; } + + DeployableSearchFilter ArmouryFilter; + ArmouryFilter.DeployableTeam = CommanderTeam; + ArmouryFilter.DeployableTypes = (STRUCTURE_MARINE_ARMOURY | STRUCTURE_MARINE_ADVARMOURY); + ArmouryFilter.IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED; + ArmouryFilter.ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING; + + AvHAIBuildableStructure* NearestArmoury = AITAC_FindClosestDeployableToLocation(Requestor->v.origin, &ArmouryFilter); + + if (!NearestArmoury) + { + NextRequest->bResponded = true; + return false; + } + + Vector DeployLocation = UTIL_GetRandomPointOnNavmeshInRadius(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), NearestArmoury->Location, UTIL_MetresToGoldSrcUnits(4.0f)); + + if (vIsZero(DeployLocation)) + { + DeployLocation = UTIL_GetRandomPointOnNavmeshInRadius(GetBaseNavProfile(MARINE_BASE_NAV_PROFILE), NearestArmoury->Location, UTIL_MetresToGoldSrcUnits(4.0f)); + } + + if (vIsZero(DeployLocation)) + { + NextRequest->bResponded = true; + return false; + } + + bool bSuccess = AICOMM_DeployItem(pBot, DEPLOYABLE_ITEM_MINES, DeployLocation); + + NextRequest->ResponseAttempts++; + + NextRequest->bResponded = bSuccess; + return true; + + } + + if (NextRequest->RequestType == BUILD_HMG) + { + if (pBot->Player->GetResources() < BALANCE_VAR(kHMGCost)) { return false; } + + DeployableSearchFilter ArmouryFilter; + ArmouryFilter.DeployableTeam = CommanderTeam; + ArmouryFilter.DeployableTypes = STRUCTURE_MARINE_ADVARMOURY; + ArmouryFilter.IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED; + ArmouryFilter.ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING; + + AvHAIBuildableStructure* NearestArmoury = AITAC_FindClosestDeployableToLocation(Requestor->v.origin, &ArmouryFilter); + + if (!NearestArmoury) + { + NextRequest->bResponded = true; + return false; + } + + Vector DeployLocation = UTIL_GetRandomPointOnNavmeshInRadius(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), NearestArmoury->Location, UTIL_MetresToGoldSrcUnits(4.0f)); + + if (vIsZero(DeployLocation)) + { + DeployLocation = UTIL_GetRandomPointOnNavmeshInRadius(GetBaseNavProfile(MARINE_BASE_NAV_PROFILE), NearestArmoury->Location, UTIL_MetresToGoldSrcUnits(4.0f)); + } + + if (vIsZero(DeployLocation)) + { + NextRequest->bResponded = true; + return false; + } + + bool bSuccess = AICOMM_DeployItem(pBot, DEPLOYABLE_ITEM_HMG, DeployLocation); + + NextRequest->ResponseAttempts++; + + NextRequest->bResponded = bSuccess; + return true; + + } + + if (NextRequest->RequestType == BUILD_PHASEGATE) + { + if (pBot->Player->GetResources() < BALANCE_VAR(kPhaseGateCost)) { return false; } + + Vector DeployLocation = UTIL_GetRandomPointOnNavmeshInRadius(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), Requestor->v.origin, UTIL_MetresToGoldSrcUnits(5.0f)); + + if (vIsZero(DeployLocation)) + { + DeployLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), Requestor->v.origin, UTIL_MetresToGoldSrcUnits(5.0f)); + } + + if (vIsZero(DeployLocation)) + { + NextRequest->bResponded = true; + return false; + } + + bool bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_PHASEGATE, DeployLocation); + + NextRequest->ResponseAttempts++; + + NextRequest->bResponded = bSuccess; + return true; + + } + + if (NextRequest->RequestType == BUILD_TURRET_FACTORY) + { + if (pBot->Player->GetResources() < BALANCE_VAR(kTurretFactoryCost)) { return false; } + + Vector DeployLocation = UTIL_GetRandomPointOnNavmeshInRadius(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), Requestor->v.origin, UTIL_MetresToGoldSrcUnits(5.0f)); + + if (vIsZero(DeployLocation)) + { + DeployLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), Requestor->v.origin, UTIL_MetresToGoldSrcUnits(5.0f)); + } + + if (vIsZero(DeployLocation)) + { + NextRequest->bResponded = true; + return false; + } + + bool bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_TURRETFACTORY, DeployLocation); + + NextRequest->ResponseAttempts++; + + NextRequest->bResponded = bSuccess; + return true; + + } + + if (NextRequest->RequestType == BUILD_TURRET) + { + if (pBot->Player->GetResources() < BALANCE_VAR(kSentryCost)) { return false; } + + DeployableSearchFilter TFFilter; + TFFilter.DeployableTeam = CommanderTeam; + TFFilter.DeployableTypes = (STRUCTURE_MARINE_TURRETFACTORY | STRUCTURE_MARINE_ADVTURRETFACTORY); + TFFilter.IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED; + TFFilter.ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING; + TFFilter.MaxSearchRadius = UTIL_MetresToGoldSrcUnits(10.0f); + + AvHAIBuildableStructure* NearestTF = AITAC_FindClosestDeployableToLocation(Requestor->v.origin, &TFFilter); + + if (!NearestTF) + { + NextRequest->bResponded = true; + return false; + } + + Vector DeployLocation = UTIL_GetRandomPointOnNavmeshInRadius(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), NearestTF->Location, UTIL_MetresToGoldSrcUnits(5.0f)); + + if (vIsZero(DeployLocation)) + { + DeployLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), NearestTF->Location, UTIL_MetresToGoldSrcUnits(5.0f)); + } + + if (vIsZero(DeployLocation)) + { + NextRequest->bResponded = true; + return false; + } + + bool bSuccess = AICOMM_DeployStructure(pBot, STRUCTURE_MARINE_TURRET, DeployLocation); + + NextRequest->ResponseAttempts++; + + NextRequest->bResponded = bSuccess; + return true; + + } + return false; } @@ -2446,6 +2764,8 @@ bool AICOMM_ShouldCommanderLeaveChair(AvHAIPlayer* pBot) if (AIMGR_GetNumHumanPlayersOnTeam(pBot->Player->GetTeam()) > 0) { return true;} } + if (IsPlayerCommander(pBot->Edict) && AIMGR_GetCommanderAllowedTime(pBot->Player->GetTeam()) > gpGlobals->time) { return true; } + int NumAliveMarinesInBase = AITAC_GetNumPlayersOfTeamInArea(pBot->Player->GetTeam(), AITAC_GetCommChairLocation(pBot->Player->GetTeam()), UTIL_MetresToGoldSrcUnits(30.0f), true, pBot->Edict, AVH_USER3_NONE); if (NumAliveMarinesInBase > 0) { return false; } @@ -2674,4 +2994,64 @@ bool AICOMM_ShouldBeacon(AvHAIPlayer* pBot) return false; +} + +void AICOMM_ReceiveChatRequest(AvHAIPlayer* Commander, edict_t* Requestor, const char* Request) +{ + AvHMessageID NewRequestType = MESSAGE_NULL; + + if (!stricmp(Request, "shotgun") || !stricmp(Request, "sg") || !stricmp(Request, "shotty")) + { + NewRequestType = BUILD_SHOTGUN; + } + else if (!stricmp(Request, "welder")) + { + NewRequestType = BUILD_WELDER; + } + else if (!stricmp(Request, "HMG")) + { + NewRequestType = BUILD_HMG; + } + else if (!stricmp(Request, "mines")) + { + NewRequestType = BUILD_MINES; + } + else if (!stricmp(Request, "cat") || !stricmp(Request, "cats") || !stricmp(Request, "catalysts")) + { + NewRequestType = BUILD_CAT; + } + else if (!stricmp(Request, "pg") || !stricmp(Request, "phase") || !stricmp(Request, "phasegate")) + { + NewRequestType = BUILD_PHASEGATE; + } + else if (!stricmp(Request, "TF") || !stricmp(Request, "turretfactory")) + { + NewRequestType = BUILD_TURRET_FACTORY; + } + else if (!stricmp(Request, "turret")) + { + NewRequestType = BUILD_TURRET; + } + else if (!stricmp(Request, "armory") || !stricmp(Request, "armoury")) + { + NewRequestType = BUILD_ARMORY; + } + + if (NewRequestType == MESSAGE_NULL) { return; } + + ai_commander_request* ExistingRequest = AICOMM_GetExistingRequestForPlayer(Commander, Requestor); + + ai_commander_request NewRequest; + ai_commander_request* RequestRef = (ExistingRequest) ? ExistingRequest : &NewRequest; + + RequestRef->bNewRequest = true; + RequestRef->bResponded = false; + RequestRef->RequestTime = gpGlobals->time; + RequestRef->RequestType = NewRequestType; + RequestRef->Requestor = Requestor; + + if (!ExistingRequest) + { + Commander->ActiveRequests.push_back(NewRequest); + } } \ No newline at end of file diff --git a/main/source/mod/AIPlayers/AvHAICommander.h b/main/source/mod/AIPlayers/AvHAICommander.h index 914fc155..c95216b5 100644 --- a/main/source/mod/AIPlayers/AvHAICommander.h +++ b/main/source/mod/AIPlayers/AvHAICommander.h @@ -69,4 +69,6 @@ const AvHAIHiveDefinition* AICOMM_GetHiveSiegeOpportunityNearestLocation(AvHAIPl bool AICOMM_ShouldCommanderPrioritiseNodes(AvHAIPlayer* pBot); bool AICOMM_ShouldBeacon(AvHAIPlayer* pBot); +void AICOMM_ReceiveChatRequest(AvHAIPlayer* Commander, edict_t* Requestor, const char* Request); + #endif // AVH_AI_COMMANDER_H \ No newline at end of file diff --git a/main/source/mod/AIPlayers/AvHAIConstants.h b/main/source/mod/AIPlayers/AvHAIConstants.h index 439fe0f8..eca5c308 100644 --- a/main/source/mod/AIPlayers/AvHAIConstants.h +++ b/main/source/mod/AIPlayers/AvHAIConstants.h @@ -677,6 +677,7 @@ typedef struct _AI_COMMANDER_REQUEST AvHMessageID RequestType = MESSAGE_NULL; // What did they request? bool bResponded = false; // Have we already responded to this request? float RequestTime = 0.0f; // When the request came in + int ResponseAttempts = 0; // How many times have we tried to respond to this request? } ai_commander_request; typedef struct AVH_AI_PLAYER diff --git a/main/source/mod/AIPlayers/AvHAINavigation.cpp b/main/source/mod/AIPlayers/AvHAINavigation.cpp index 5c4de2d8..eb62e16d 100644 --- a/main/source/mod/AIPlayers/AvHAINavigation.cpp +++ b/main/source/mod/AIPlayers/AvHAINavigation.cpp @@ -2965,28 +2965,19 @@ void NewMove(AvHAIPlayer* pBot) break; case SAMPLE_POLYFLAGS_WALLCLIMB: { - if (IsPlayerSkulk(pBot->Edict)) + if (PlayerHasWeapon(pBot->Player, WEAPON_FADE_BLINK)) { - WallClimbMove(pBot, MoveFrom, MoveTo, pBot->BotNavInfo.CurrentPathPoint->requiredZ); + BlinkClimbMove(pBot, MoveFrom, MoveTo, pBot->BotNavInfo.CurrentPathPoint->requiredZ); } else { - BlinkClimbMove(pBot, MoveFrom, MoveTo, pBot->BotNavInfo.CurrentPathPoint->requiredZ); + WallClimbMove(pBot, MoveFrom, MoveTo, pBot->BotNavInfo.CurrentPathPoint->requiredZ); } } break; case SAMPLE_POLYFLAGS_LADDER: - { - if (IsPlayerSkulk(pBot->Edict)) - { - LadderMove(pBot, MoveFrom, MoveTo, pBot->BotNavInfo.CurrentPathPoint->requiredZ, NextArea); - } - else - { - LadderMove(pBot, MoveFrom, MoveTo, pBot->BotNavInfo.CurrentPathPoint->requiredZ, NextArea); - } - } - break; + LadderMove(pBot, MoveFrom, MoveTo, pBot->BotNavInfo.CurrentPathPoint->requiredZ, NextArea); + break; case SAMPLE_POLYFLAGS_TEAM1PHASEGATE: case SAMPLE_POLYFLAGS_TEAM2PHASEGATE: PhaseGateMove(pBot, MoveFrom, MoveTo); @@ -3247,25 +3238,27 @@ void LadderMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector EndPoin bool bIsGoingUpLadder = (EndPoint.z > StartPoint.z); + // Stop holding crouch if we're a skulk so we can climb up/down + if (IsPlayerSkulk(pBot->Edict)) + { + pBot->Button &= ~IN_DUCK; + } + if (IsPlayerOnLadder(pBot->Edict)) { // We're on the ladder and actively climbing - Vector CurrentLadderNormal = UTIL_GetNearestLadderNormal(pBot->Edict); - CurrentLadderNormal = UTIL_GetVectorNormal2D(CurrentLadderNormal); + Vector CurrentLadderNormal = UTIL_GetNearestLadderNormal(pBot->CollisionHullBottomLocation + Vector(0.0f, 0.0f, 5.0f)); + //CurrentLadderNormal = UTIL_GetVectorNormal2D(CurrentLadderNormal); if (vIsZero(CurrentLadderNormal)) { - CurrentLadderNormal = UTIL_GetVectorNormal2D(EndPoint - StartPoint); + CurrentLadderNormal = UTIL_GetVectorNormal2D(EndPoint - pBot->Edict->v.origin); } + UTIL_DrawLine(INDEXENT(1), pBot->Edict->v.origin, pBot->Edict->v.origin + (CurrentLadderNormal * 100.0f), 0.5f); + const Vector LadderRightNormal = UTIL_GetVectorNormal(UTIL_GetCrossProduct(CurrentLadderNormal, UP_VECTOR)); - // Stop holding crouch if we're a skulk so we can climb up/down - if (IsPlayerSkulk(pBot->Edict)) - { - pBot->Button &= ~IN_DUCK; - } - Vector ClimbRightNormal = LadderRightNormal; if (bIsGoingUpLadder) @@ -3312,7 +3305,7 @@ void LadderMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector EndPoin bool bHittingHead = !UTIL_QuickTrace(pBot->Edict, HeadTraceLocation, HeadTraceLocation + Vector(0.0f, 0.0f, 10.0f)); bool bClimbIntoVent = (NextArea == SAMPLE_POLYAREA_CROUCH); - if (bHittingHead || bClimbIntoVent) + if (!IsPlayerSkulk(pBot->Edict) && (bHittingHead || bClimbIntoVent)) { pBot->Button |= IN_DUCK; } @@ -4083,7 +4076,7 @@ void WallClimbMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector EndP float ZDiff = fabs(pEdict->v.origin.z - RequiredClimbHeight); Vector AdjustedTargetLocation = EndPoint + (UTIL_GetVectorNormal2D(EndPoint - StartPoint) * 1000.0f); - Vector DirectAheadView = pBot->CurrentEyePosition + (UTIL_GetVectorNormal2D(AdjustedTargetLocation - pEdict->v.origin) * 10.0f); + Vector DirectAheadView = pBot->CurrentEyePosition + (UTIL_GetVectorNormal2D(AdjustedTargetLocation - pBot->CurrentEyePosition) * 100.0f); Vector ClimbSurfaceNormal = UTIL_GetVectorNormal(EndPoint - StartPoint); @@ -4111,7 +4104,7 @@ void WallClimbMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector EndP } else { - if (ZDiff > 32.0f) + if (ZDiff > 16.0f) { ClimbSurfaceNormal = ClimbSurfaceNormal; LookLocation = pBot->CurrentEyePosition + (ClimbSurfaceNormal * 100.0f); @@ -5069,7 +5062,15 @@ bool AbortCurrentMove(AvHAIPlayer* pBot, const Vector NewDestination) } else { - WallClimbMove(pBot, MoveFrom, MoveTo, pBot->BotNavInfo.CurrentPathPoint->requiredZ); + if (PlayerHasWeapon(pBot->Player, WEAPON_FADE_BLINK)) + { + BlinkClimbMove(pBot, MoveFrom, MoveTo, pBot->BotNavInfo.CurrentPathPoint->requiredZ); + } + else + { + WallClimbMove(pBot, MoveFrom, MoveTo, pBot->BotNavInfo.CurrentPathPoint->requiredZ); + } + } } diff --git a/main/source/mod/AIPlayers/AvHAIPlayerManager.cpp b/main/source/mod/AIPlayers/AvHAIPlayerManager.cpp index 9404aeb3..c246edc5 100644 --- a/main/source/mod/AIPlayers/AvHAIPlayerManager.cpp +++ b/main/source/mod/AIPlayers/AvHAIPlayerManager.cpp @@ -6,6 +6,7 @@ #include "AvHAIConfig.h" #include "AvHAIWeaponHelper.h" #include "AvHAIHelper.h" +#include "AvHAICommander.h" #include "../AvHGamerules.h" #include "../dlls/client.h" #include @@ -33,6 +34,9 @@ bool bMapDataInitialised = false; bool bTestNavigation = false; bool bDroneMode = false; +float NextCommanderAllowedTimeTeamA = 0.0f; +float NextCommanderAllowedTimeTeamB = 0.0f; + extern int m_spriteTexture; Vector DebugVector1 = ZERO_VECTOR; @@ -92,6 +96,11 @@ AvHAICommanderMode AIMGR_GetCommanderMode() } +float AIMGR_GetCommanderAllowedTime(AvHTeamNumber Team) +{ + return (Team == GetGameRules()->GetTeamANumber()) ? NextCommanderAllowedTimeTeamA : NextCommanderAllowedTimeTeamB; +} + void AIMGR_UpdateAIPlayerCounts() { for (auto BotIt = ActiveAIPlayers.begin(); BotIt != ActiveAIPlayers.end();) @@ -597,6 +606,8 @@ void AIMGR_UpdateAIPlayers() float FrameDelta = CurrTime - PrevTime; float ThinkDelta = CurrTime - LastThinkTime; + + for (auto BotIt = ActiveAIPlayers.begin(); BotIt != ActiveAIPlayers.end();) { @@ -627,6 +638,31 @@ void AIMGR_UpdateAIPlayers() } } + if (bHasRoundStarted) + { + AvHTeamNumber TeamANumber = GetGameRules()->GetTeamANumber(); + AvHTeamNumber TeamBNumber = GetGameRules()->GetTeamBNumber(); + + AvHTeam* TeamA = GetGameRules()->GetTeam(TeamANumber); + AvHTeam* TeamB = GetGameRules()->GetTeam(TeamBNumber); + + if (TeamA->GetTeamType() == AVH_CLASS_TYPE_MARINE) + { + if (TeamA->GetCommanderPlayer() && !(TeamA->GetCommanderPlayer()->pev->flags & FL_FAKECLIENT)) + { + AIMGR_SetCommanderAllowedTime(TeamANumber, gpGlobals->time + 15.0f); + } + } + + if (TeamB->GetTeamType() == AVH_CLASS_TYPE_MARINE) + { + if (TeamB->GetCommanderPlayer() && !(TeamB->GetCommanderPlayer()->pev->flags & FL_FAKECLIENT)) + { + AIMGR_SetCommanderAllowedTime(TeamBNumber, gpGlobals->time + 15.0f); + } + } + } + if (bHasRoundStarted && ShouldBotThink(bot)) { if (bot->bIsInactive) @@ -877,6 +913,41 @@ void AIMGR_ResetRound() void AIMGR_RoundStarted() { bHasRoundStarted = true; + + AvHTeamNumber TeamANumber = GetGameRules()->GetTeamANumber(); + AvHTeamNumber TeamBNumber = GetGameRules()->GetTeamANumber(); + + // If our team has no humans on it, then we can take command right away. Otherwise, wait the allotted grace period to allow the human to take command + + if (AIMGR_GetNumHumanPlayersOnTeam(TeamANumber) > 0) + { + AIMGR_SetCommanderAllowedTime(TeamANumber, gpGlobals->time + CONFIG_GetCommanderWaitTime()); + } + else + { + AIMGR_SetCommanderAllowedTime(TeamANumber, 0.0f); + } + + if (AIMGR_GetNumHumanPlayersOnTeam(TeamBNumber) > 0) + { + AIMGR_SetCommanderAllowedTime(TeamBNumber, gpGlobals->time + CONFIG_GetCommanderWaitTime()); + } + else + { + AIMGR_SetCommanderAllowedTime(TeamBNumber, 0.0f); + } +} + +void AIMGR_SetCommanderAllowedTime(AvHTeamNumber Team, float NewValue) +{ + if (Team == GetGameRules()->GetTeamANumber()) + { + NextCommanderAllowedTimeTeamA = NewValue; + } + else + { + NextCommanderAllowedTimeTeamB = NewValue; + } } void AIMGR_ClearBotData() @@ -944,7 +1015,7 @@ AvHAIPlayer* AIMGR_GetAICommander(AvHTeamNumber Team) { AvHPlayer* ActiveCommander = GetGameRules()->GetTeam(Team)->GetCommanderPlayer(); - if (!ActiveCommander) { return nullptr; } + if (!ActiveCommander || !(ActiveCommander->pev->flags & FL_FAKECLIENT)) { return nullptr; } for (auto it = ActiveAIPlayers.begin(); it != ActiveAIPlayers.end(); it++) { @@ -1113,4 +1184,21 @@ bool AIMGR_GetTestNavMode() bool AIMGR_GetDroneMode() { return bTestNavigation; +} + +void AIMGR_ReceiveCommanderRequest(AvHTeamNumber Team, edict_t* Requestor, const char* Request) +{ + AvHTeam* TeamRef = GetGameRules()->GetTeam(Team); + + if (!TeamRef || TeamRef->GetTeamType() != AVH_CLASS_TYPE_MARINE) + { + return; + } + + AvHAIPlayer* BotCommander = AIMGR_GetAICommander(Team); + + if (BotCommander) + { + AICOMM_ReceiveChatRequest(BotCommander, Requestor, Request); + } } \ No newline at end of file diff --git a/main/source/mod/AIPlayers/AvHAIPlayerManager.h b/main/source/mod/AIPlayers/AvHAIPlayerManager.h index ea3d509c..b4677f09 100644 --- a/main/source/mod/AIPlayers/AvHAIPlayerManager.h +++ b/main/source/mod/AIPlayers/AvHAIPlayerManager.h @@ -49,6 +49,9 @@ void AIMGR_UpdateAIMapData(); AvHAICommanderMode AIMGR_GetCommanderMode(); +void AIMGR_SetCommanderAllowedTime(AvHTeamNumber Team, float NewValue); +float AIMGR_GetCommanderAllowedTime(AvHTeamNumber Team); + Vector AIDEBUG_GetDebugVector1(); Vector AIDEBUG_GetDebugVector2(); void AIDEBUG_SetDebugVector1(const Vector NewVector); @@ -93,4 +96,6 @@ bool AIMGR_GetTestNavMode(); void AIMGR_SetDroneMode(bool bNewValue); bool AIMGR_GetDroneMode(); +void AIMGR_ReceiveCommanderRequest(AvHTeamNumber Team, edict_t* Requestor, const char* Request); + #endif \ No newline at end of file diff --git a/main/source/mod/AIPlayers/AvHAIPlayerUtil.cpp b/main/source/mod/AIPlayers/AvHAIPlayerUtil.cpp index 8889b145..3be1942f 100644 --- a/main/source/mod/AIPlayers/AvHAIPlayerUtil.cpp +++ b/main/source/mod/AIPlayers/AvHAIPlayerUtil.cpp @@ -848,21 +848,161 @@ Vector UTIL_GetNearestLadderNormal(Vector SearchLocation) if (closestLadderRef) { - Vector CentrePoint = closestLadderRef->pev->absmin + ((closestLadderRef->pev->absmax - closestLadderRef->pev->absmin) * 0.5f); - CentrePoint.z = SearchLocation.z; - if (vPointOverlaps3D(SearchLocation, closestLadderRef->pev->absmin, closestLadderRef->pev->absmax)) { - CentrePoint = SearchLocation; - CentrePoint.z = closestLadderRef->pev->absmin.z; + Vector Trace1End, Trace2End, Trace3End, Trace4End, Trace5End, Trace6End, Trace7End, Trace8End; + Trace1End = Trace2End = Trace3End = Trace4End = Trace5End = Trace6End = Trace7End = Trace8End = SearchLocation; + + Trace1End.x += 32.0f; + Trace1End.y += 32.0f; + + Trace2End.x += 32.0f; + Trace2End.y -= 32.0f; + + Trace3End.x -= 32.0f; + Trace3End.y -= 32.0f; + + Trace4End.x -= 32.0f; + Trace4End.y += 32.0f; + + Trace5End.x += 32.0f; + + Trace6End.x -= 32.0f; + + Trace7End.y -= 32.0f; + + Trace8End.y += 32.0f; + + Vector ClosestNormal = ZERO_VECTOR; + float MinDist = 0.0f; + + trace_t TraceResult; + NS_TraceLine(SearchLocation, Trace1End, 1, PM_NORMAL, -1, true, TraceResult); + + UTIL_DrawLine(INDEXENT(1), SearchLocation, Trace1End, 0.5f, 255, 0, 0); + + if (TraceResult.fraction < 1.0f) + { + int PointContents = UTIL_PointContents(TraceResult.endpos); + + if (vIsZero(ClosestNormal) || TraceResult.fraction < MinDist) + { + ClosestNormal = TraceResult.plane.normal; + MinDist = TraceResult.fraction; + } + } + + UTIL_DrawLine(INDEXENT(1), SearchLocation, Trace2End, 0.5f, 0, 128, 0); + + NS_TraceLine(SearchLocation, Trace2End, 1, PM_NORMAL, -1, true, TraceResult); + + if (TraceResult.fraction < 1.0f) + { + int PointContents = UTIL_PointContents(TraceResult.endpos); + + if (vIsZero(ClosestNormal) || TraceResult.fraction < MinDist) + { + ClosestNormal = TraceResult.plane.normal; + MinDist = TraceResult.fraction; + } + } + + UTIL_DrawLine(INDEXENT(1), SearchLocation, Trace3End, 0.5f, 0, 0, 255); + + NS_TraceLine(SearchLocation, Trace3End, 1, PM_NORMAL, -1, true, TraceResult); + + if (TraceResult.fraction < 1.0f) + { + int PointContents = UTIL_PointContents(TraceResult.endpos); + + if (vIsZero(ClosestNormal) || TraceResult.fraction < MinDist) + { + ClosestNormal = TraceResult.plane.normal; + MinDist = TraceResult.fraction; + } + } + + UTIL_DrawLine(INDEXENT(1), SearchLocation, Trace4End, 0.5f, 255, 255, 0); + + NS_TraceLine(SearchLocation, Trace4End, 1, PM_NORMAL, -1, true, TraceResult); + + if (TraceResult.fraction < 1.0f) + { + int PointContents = UTIL_PointContents(TraceResult.endpos); + + if (vIsZero(ClosestNormal) || TraceResult.fraction < MinDist) + { + ClosestNormal = TraceResult.plane.normal; + MinDist = TraceResult.fraction; + } + } + + NS_TraceLine(SearchLocation, Trace5End, 1, PM_NORMAL, -1, true, TraceResult); + + if (TraceResult.fraction < 1.0f) + { + int PointContents = UTIL_PointContents(TraceResult.endpos); + + if (vIsZero(ClosestNormal) || TraceResult.fraction < MinDist) + { + ClosestNormal = TraceResult.plane.normal; + MinDist = TraceResult.fraction; + } + } + + NS_TraceLine(SearchLocation, Trace6End, 1, PM_NORMAL, -1, true, TraceResult); + + if (TraceResult.fraction < 1.0f) + { + int PointContents = UTIL_PointContents(TraceResult.endpos); + + if (vIsZero(ClosestNormal) || TraceResult.fraction < MinDist) + { + ClosestNormal = TraceResult.plane.normal; + MinDist = TraceResult.fraction; + } + } + + NS_TraceLine(SearchLocation, Trace7End, 1, PM_NORMAL, -1, true, TraceResult); + + if (TraceResult.fraction < 1.0f) + { + int PointContents = UTIL_PointContents(TraceResult.endpos); + + if (vIsZero(ClosestNormal) || TraceResult.fraction < MinDist) + { + ClosestNormal = TraceResult.plane.normal; + MinDist = TraceResult.fraction; + } + } + + NS_TraceLine(SearchLocation, Trace8End, 1, PM_NORMAL, -1, true, TraceResult); + + if (TraceResult.fraction < 1.0f) + { + int PointContents = UTIL_PointContents(TraceResult.endpos); + + if (vIsZero(ClosestNormal) || TraceResult.fraction < MinDist) + { + ClosestNormal = TraceResult.plane.normal; + MinDist = TraceResult.fraction; + } + } + + return ClosestNormal; } - - trace_t TraceResult; - NS_TraceLine(SearchLocation, CentrePoint, 1, PM_WORLD_ONLY, -1, true, TraceResult); - - if (TraceResult.fraction < 1.0f) + else { - return TraceResult.plane.normal; + Vector CentrePoint = closestLadderRef->pev->absmin + (closestLadderRef->pev->size * 0.5f); + CentrePoint.z = SearchLocation.z; + + trace_t TraceResult; + NS_TraceLine(SearchLocation, CentrePoint, 1, PM_WORLD_ONLY, -1, true, TraceResult); + + if (TraceResult.fraction < 1.0f) + { + return TraceResult.plane.normal; + } } } diff --git a/main/source/mod/AIPlayers/AvHAITactical.cpp b/main/source/mod/AIPlayers/AvHAITactical.cpp index e015fe44..edfac850 100644 --- a/main/source/mod/AIPlayers/AvHAITactical.cpp +++ b/main/source/mod/AIPlayers/AvHAITactical.cpp @@ -4721,3 +4721,26 @@ edict_t* AITAC_GetLastSeenLerkForTeam(AvHTeamNumber Team, float& LastSeenTime) return LastSeenLerkTeamB; } } + +bool AITAC_IsCompletedStructureOfTypeNearLocation(AvHTeamNumber Team, unsigned int StructureType, Vector SearchLocation, float SearchRadius) +{ + DeployableSearchFilter SearchFilter; + SearchFilter.DeployableTeam = Team; + SearchFilter.DeployableTypes = StructureType; + SearchFilter.IncludeStatusFlags = STRUCTURE_STATUS_COMPLETED; + SearchFilter.ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING; + SearchFilter.MaxSearchRadius = SearchRadius; + + return AITAC_DeployableExistsAtLocation(SearchLocation, &SearchFilter); +} + +bool AITAC_IsStructureOfTypeNearLocation(AvHTeamNumber Team, unsigned int StructureType, Vector SearchLocation, float SearchRadius) +{ + DeployableSearchFilter SearchFilter; + SearchFilter.DeployableTeam = Team; + SearchFilter.DeployableTypes = StructureType; + SearchFilter.ExcludeStatusFlags = STRUCTURE_STATUS_RECYCLING; + SearchFilter.MaxSearchRadius = SearchRadius; + + return AITAC_DeployableExistsAtLocation(SearchLocation, &SearchFilter); +} \ No newline at end of file diff --git a/main/source/mod/AIPlayers/AvHAITactical.h b/main/source/mod/AIPlayers/AvHAITactical.h index f4f887f5..247d0cee 100644 --- a/main/source/mod/AIPlayers/AvHAITactical.h +++ b/main/source/mod/AIPlayers/AvHAITactical.h @@ -189,4 +189,7 @@ int AITAC_GetNumWeaponsInPlay(AvHTeamNumber Team, AvHAIWeapon WeaponType); edict_t* AITAC_GetLastSeenLerkForTeam(AvHTeamNumber Team, float& LastSeenTime); +bool AITAC_IsCompletedStructureOfTypeNearLocation(AvHTeamNumber Team, unsigned int StructureType, Vector SearchLocation, float SearchRadius); +bool AITAC_IsStructureOfTypeNearLocation(AvHTeamNumber Team, unsigned int StructureType, Vector SearchLocation, float SearchRadius); + #endif \ No newline at end of file diff --git a/main/source/mod/AIPlayers/AvHAITask.cpp b/main/source/mod/AIPlayers/AvHAITask.cpp index 6aae9c71..e7a52033 100644 --- a/main/source/mod/AIPlayers/AvHAITask.cpp +++ b/main/source/mod/AIPlayers/AvHAITask.cpp @@ -1752,9 +1752,7 @@ void BotProgressTakeCommandTask(AvHAIPlayer* pBot) } else { - float CommanderWaitTime = CONFIG_GetCommanderWaitTime(); - - if ((gpGlobals->time - GetGameRules()->GetTimeGameStarted()) > CommanderWaitTime) + if (gpGlobals->time > AIMGR_GetCommanderAllowedTime(pBot->Player->GetTeam())) { BotUseObject(pBot, CommChair, false); } @@ -1764,7 +1762,7 @@ void BotProgressTakeCommandTask(AvHAIPlayer* pBot) if (FNullEnt(NearestHuman)) { - BotUseObject(pBot, CommChair, false); + BotGuardLocation(pBot, CommChair->v.origin); } else { diff --git a/main/source/mod/AvHConstants.h b/main/source/mod/AvHConstants.h index 13653842..e76ff12b 100644 --- a/main/source/mod/AvHConstants.h +++ b/main/source/mod/AvHConstants.h @@ -942,6 +942,8 @@ const float kCommanderHierarchyScaleFactor = .0002f; #define kReadyNotification "ready" #define kNotReadyNotification "notready" +#define kAICommanderRequest "comm" + const int kOverwatchBreakingVelocity = 5; const float kOverwatchAcquireTime = 6.0f; const float kOverwatchLostTargetTime = 4.0f; diff --git a/main/source/mod/AvHMarineEquipment.cpp b/main/source/mod/AvHMarineEquipment.cpp index 6cc8f1e7..ff97ae97 100644 --- a/main/source/mod/AvHMarineEquipment.cpp +++ b/main/source/mod/AvHMarineEquipment.cpp @@ -146,6 +146,8 @@ #include "AvHSiegeTurret.h" #include "AvHHulls.h" +#include "AIPlayers/AvHAIPlayerManager.h" + //LINK_ENTITY_TO_CLASS(kwMine, AvHMine); //LINK_ENTITY_TO_CLASS(kwDeployedTurret, AvHDeployedTurret); //LINK_ENTITY_TO_CLASS(kwTurret, AvHTurret); @@ -1991,6 +1993,12 @@ void AvHCommandStation::CommandUse( CBaseEntity* pActivator, CBaseEntity* pCalle // The player somehow touches the command station while still a commander if(thePlayer->GetUser3() != AVH_USER3_COMMANDER_PLAYER) { + // A human used the comm chair, kick the AI commander out if they're in there and don't let them re-enter for 20 seconds + if (!(thePlayer->pev->flags & FL_FAKECLIENT)) + { + AIMGR_SetCommanderAllowedTime(theStationTeamNumber, gpGlobals->time + 20.0f); + } + thePlayer->SendMessage(kCommandStationInUse, TOOLTIP); } } diff --git a/main/source/mod/AvHTeam.cpp b/main/source/mod/AvHTeam.cpp index 96d64c79..021a20b3 100644 --- a/main/source/mod/AvHTeam.cpp +++ b/main/source/mod/AvHTeam.cpp @@ -158,6 +158,8 @@ #include "AvHNetworkMessages.h" #include "AvHNexusServer.h" +#include "AIPlayers/AvHAIPlayerManager.h" + extern int gPhaseInEventID; extern cvar_t avh_votecasttime; extern cvar_t avh_votedowntime; @@ -721,6 +723,10 @@ bool AvHTeam::PlayerVote(int inPlayerIndex, string& outPlayerMessage) if(theCommander) { theCommander->LogPlayerActionPlayer(theVotingPlayer, "votedown"); + if (theCommander->pev->flags & FL_FAKECLIENT) + { + AIMGR_SetCommanderAllowedTime(theVotingPlayer->GetTeam(), gpGlobals->time + 60.0f); + } } } }