Merge pull request #177 from RGreenlees/BotHearing

Bot hearing
This commit is contained in:
pierow 2024-04-22 03:26:18 -04:00 committed by GitHub
commit c710fa347a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
26 changed files with 688 additions and 222 deletions

Binary file not shown.

View File

@ -30,7 +30,7 @@ MarineReactionTime=0.4
MarineAimSkill=0.1 MarineAimSkill=0.1
MarineMovementTracking=0.1 MarineMovementTracking=0.1
MarineViewSpeed=0.5 MarineViewSpeed=0.5
AlienReactionTime=0.4 AlienReactionTime=0.5
AlienAimSkill=0.2 AlienAimSkill=0.2
AlienMovementTracking=0.2 AlienMovementTracking=0.2
AlienViewSpeed=0.75 AlienViewSpeed=0.75
@ -89,4 +89,4 @@ TeamSize=co_kestrel:5/5
# ChamberSequence:movement/?/? # ChamberSequence:movement/?/?
# Or if you want sensory always last, but movement and defence random, use # Or if you want sensory always last, but movement and defence random, use
# ChamberSequence=?/?/sensory # ChamberSequence=?/?/sensory
ChamberSequence=defense/movement/sensory ChamberSequence=?/?/?

View File

@ -256,6 +256,7 @@
<ClCompile Include="..\mod\AvHAIPlayer.cpp" /> <ClCompile Include="..\mod\AvHAIPlayer.cpp" />
<ClCompile Include="..\mod\AvHAIPlayerManager.cpp" /> <ClCompile Include="..\mod\AvHAIPlayerManager.cpp" />
<ClCompile Include="..\mod\AvHAIPlayerUtil.cpp" /> <ClCompile Include="..\mod\AvHAIPlayerUtil.cpp" />
<ClCompile Include="..\mod\AvHAISoundQueue.cpp" />
<ClCompile Include="..\mod\AvHAITactical.cpp" /> <ClCompile Include="..\mod\AvHAITactical.cpp" />
<ClCompile Include="..\mod\AvHAITask.cpp" /> <ClCompile Include="..\mod\AvHAITask.cpp" />
<ClCompile Include="..\mod\AvHAIWeaponHelper.cpp" /> <ClCompile Include="..\mod\AvHAIWeaponHelper.cpp" />
@ -1390,6 +1391,7 @@
<ClInclude Include="..\mod\AvHAIPlayer.h" /> <ClInclude Include="..\mod\AvHAIPlayer.h" />
<ClInclude Include="..\mod\AvHAIPlayerManager.h" /> <ClInclude Include="..\mod\AvHAIPlayerManager.h" />
<ClInclude Include="..\mod\AvHAIPlayerUtil.h" /> <ClInclude Include="..\mod\AvHAIPlayerUtil.h" />
<ClInclude Include="..\mod\AvHAISoundQueue.h" />
<ClInclude Include="..\mod\AvHAITactical.h" /> <ClInclude Include="..\mod\AvHAITactical.h" />
<ClInclude Include="..\mod\AvHAITask.h" /> <ClInclude Include="..\mod\AvHAITask.h" />
<ClInclude Include="..\mod\AvHAIWeaponHelper.h" /> <ClInclude Include="..\mod\AvHAIWeaponHelper.h" />

View File

@ -545,6 +545,9 @@
<ClCompile Include="..\mod\AvHAIPlayer.cpp"> <ClCompile Include="..\mod\AvHAIPlayer.cpp">
<Filter>mod\bots</Filter> <Filter>mod\bots</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\mod\AvHAISoundQueue.cpp">
<Filter>mod\bots</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="activity.h"> <ClInclude Include="activity.h">
@ -967,5 +970,8 @@
<ClInclude Include="..\mod\AvHAIPlayer.h"> <ClInclude Include="..\mod\AvHAIPlayer.h">
<Filter>mod\bots</Filter> <Filter>mod\bots</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\mod\AvHAISoundQueue.h">
<Filter>mod\bots</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -25,6 +25,10 @@
#include "gamerules.h" #include "gamerules.h"
#include "../mod/AvHSpecials.h" #include "../mod/AvHSpecials.h"
#ifdef AVH_SERVER
#include "../mod/AvHAIPlayerManager.h"
#endif
static char *memfgets( byte *pMemFile, int fileSize, int &filePos, char *pBuffer, int bufferSize ); static char *memfgets( byte *pMemFile, int fileSize, int &filePos, char *pBuffer, int bufferSize );
@ -1429,7 +1433,9 @@ void EMIT_SOUND_DYN(edict_t *entity, int channel, const char *sample, float volu
ALERT( at_aiconsole, "Unable to find %s in sentences.txt\n", sample ); ALERT( at_aiconsole, "Unable to find %s in sentences.txt\n", sample );
} }
else else
{
EMIT_SOUND_DYN2(entity, channel, sample, volume, attenuation, flags, pitch); EMIT_SOUND_DYN2(entity, channel, sample, volume, attenuation, flags, pitch);
}
} }
// play a specific sentence over the HEV suit speaker - just pass player entity, and !sentencename // play a specific sentence over the HEV suit speaker - just pass player entity, and !sentencename

View File

@ -718,7 +718,7 @@ void CONFIG_RegenerateIniFile()
fprintf(NewConfigFile, "# ChamberSequence:movement/?/?\n"); fprintf(NewConfigFile, "# ChamberSequence:movement/?/?\n");
fprintf(NewConfigFile, "# Or if you want sensory always last, but movement and defence random, use\n"); fprintf(NewConfigFile, "# Or if you want sensory always last, but movement and defence random, use\n");
fprintf(NewConfigFile, "# ChamberSequence=?/?/sensory\n"); fprintf(NewConfigFile, "# ChamberSequence=?/?/sensory\n");
fprintf(NewConfigFile, "ChamberSequence=defense/movement/sensory\n"); fprintf(NewConfigFile, "ChamberSequence=?/?/?\n");
fflush(NewConfigFile); fflush(NewConfigFile);
fclose(NewConfigFile); fclose(NewConfigFile);

View File

@ -497,6 +497,7 @@ typedef struct _ENEMY_STATUS
float NextUpdateTime = 0.0f; // When the bot can next react to a change in target's state float NextUpdateTime = 0.0f; // When the bot can next react to a change in target's state
float NextVelocityUpdateTime = 0.0f; // When the bot can next react to a change in target's state float NextVelocityUpdateTime = 0.0f; // When the bot can next react to a change in target's state
float EndTrackingTime = 0.0f; // When to stop "sensing" enemy movement after losing LOS float EndTrackingTime = 0.0f; // When to stop "sensing" enemy movement after losing LOS
float CertaintyOfLocation = 0.0f; // How sure the bot is where the enemy is if they're cloaked
} enemy_status; } enemy_status;
@ -804,6 +805,8 @@ typedef struct AVH_AI_PLAYER
float ServerUpdateDelta = 0.0f; // How long since we last called RunPlayerMove float ServerUpdateDelta = 0.0f; // How long since we last called RunPlayerMove
float LastServerUpdateTime = 0.0f; // When we last called RunPlayerMove float LastServerUpdateTime = 0.0f; // When we last called RunPlayerMove
float HearingThreshold = 0.0f; // How loud does a sound need to be before the bot detects it? This is set when hearing a sound so that louder sounds drown out quieter ones, and decrements quickly
} AvHAIPlayer; } AvHAIPlayer;

View File

@ -2059,7 +2059,7 @@ dtStatus FindPathClosestToPoint(AvHAIPlayer* pBot, const BotMoveStyle MoveStyle,
Vector FromFloorLocation = AdjustPointForPathfinding(FromLocation); Vector FromFloorLocation = AdjustPointForPathfinding(FromLocation);
nav_door* LiftReference = UTIL_GetNavDoorByEdict(pBot->Edict->v.groundentity); nav_door* LiftReference = UTIL_GetLiftReferenceByEdict(pBot->Edict->v.groundentity);
bool bMustDisembarkLiftFirst = false; bool bMustDisembarkLiftFirst = false;
Vector LiftStart = ZERO_VECTOR; Vector LiftStart = ZERO_VECTOR;
Vector LiftEnd = ZERO_VECTOR; Vector LiftEnd = ZERO_VECTOR;
@ -3691,11 +3691,16 @@ void StructureBlockedMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vect
void BlockedMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector EndPoint) void BlockedMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector EndPoint)
{ {
Vector vForward = UTIL_GetVectorNormal2D(EndPoint - StartPoint); Vector vForward = UTIL_GetVectorNormal2D(EndPoint - pBot->Edict->v.origin);
if (vIsZero(vForward)) if (vIsZero(vForward))
{ {
vForward = UTIL_GetForwardVector2D(pBot->Edict->v.angles); vForward = UTIL_GetVectorNormal2D(EndPoint - StartPoint);
if (vIsZero(vForward))
{
vForward = UTIL_GetForwardVector2D(pBot->Edict->v.angles);
}
} }
pBot->desiredMovementDir = vForward; pBot->desiredMovementDir = vForward;
@ -3713,6 +3718,10 @@ void BlockedMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector EndPoi
if (FaceDot < 0.95f) if (FaceDot < 0.95f)
{ {
float MoveSpeed = vSize2D(pBot->Edict->v.velocity); float MoveSpeed = vSize2D(pBot->Edict->v.velocity);
if (MoveSpeed < 20.0f)
{
MoveSpeed = 100.0f;
}
Vector NewVelocity = vForward * MoveSpeed; Vector NewVelocity = vForward * MoveSpeed;
NewVelocity.z = pBot->Edict->v.velocity.z; NewVelocity.z = pBot->Edict->v.velocity.z;
@ -3729,6 +3738,11 @@ void JumpMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector EndPoint)
if (vIsZero(vForward)) if (vIsZero(vForward))
{ {
vForward = UTIL_GetVectorNormal2D(EndPoint - StartPoint); vForward = UTIL_GetVectorNormal2D(EndPoint - StartPoint);
if (vIsZero(vForward))
{
vForward = UTIL_GetForwardVector2D(pBot->Edict->v.angles);
}
} }
pBot->desiredMovementDir = vForward; pBot->desiredMovementDir = vForward;
@ -3746,6 +3760,10 @@ void JumpMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector EndPoint)
if (FaceDot < 0.95f) if (FaceDot < 0.95f)
{ {
float MoveSpeed = vSize2D(pBot->Edict->v.velocity); float MoveSpeed = vSize2D(pBot->Edict->v.velocity);
if (MoveSpeed < 20.0f)
{
MoveSpeed = 100.0f;
}
Vector NewVelocity = vForward * MoveSpeed; Vector NewVelocity = vForward * MoveSpeed;
NewVelocity.z = pBot->Edict->v.velocity.z; NewVelocity.z = pBot->Edict->v.velocity.z;
@ -4729,7 +4747,7 @@ void BlinkClimbMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector End
if (GetPlayerCurrentWeapon(pBot->Player) != WEAPON_FADE_BLINK) { return; } if (GetPlayerCurrentWeapon(pBot->Player) != WEAPON_FADE_BLINK) { return; }
// Only blink if we're below the target climb height // Only blink if we're below the target climb height
if (pEdict->v.origin.z < RequiredClimbHeight + 32.0f) if (pEdict->v.origin.z < RequiredClimbHeight + 4.0f)
{ {
float HeightToClimb = (fabsf(pEdict->v.origin.z - RequiredClimbHeight)); float HeightToClimb = (fabsf(pEdict->v.origin.z - RequiredClimbHeight));
@ -4746,6 +4764,12 @@ void BlinkClimbMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector End
if (FaceDot < 0.95f) if (FaceDot < 0.95f)
{ {
float MoveSpeed = vSize2D(pBot->Edict->v.velocity); float MoveSpeed = vSize2D(pBot->Edict->v.velocity);
if (MoveSpeed < 20.0f)
{
MoveSpeed = 100.0f;
}
Vector NewVelocity = MoveDir * MoveSpeed; Vector NewVelocity = MoveDir * MoveSpeed;
NewVelocity.z = pBot->Edict->v.velocity.z; NewVelocity.z = pBot->Edict->v.velocity.z;
@ -6365,6 +6389,7 @@ bool MoveTo(AvHAIPlayer* pBot, const Vector Destination, const BotMoveStyle Move
{ {
pBot->BotNavInfo.StuckInfo.bPathFollowFailed = false; pBot->BotNavInfo.StuckInfo.bPathFollowFailed = false;
ClearBotMovement(pBot); ClearBotMovement(pBot);
return true; return true;
} }
@ -6811,6 +6836,7 @@ void BotFollowSwimPath(AvHAIPlayer* pBot)
if (pBot->BotNavInfo.CurrentPath.size() == 0 || pBot->BotNavInfo.CurrentPathPoint >= pBot->BotNavInfo.CurrentPath.size()) if (pBot->BotNavInfo.CurrentPath.size() == 0 || pBot->BotNavInfo.CurrentPathPoint >= pBot->BotNavInfo.CurrentPath.size())
{ {
ClearBotPath(pBot); ClearBotPath(pBot);
NAV_ClearMovementTask(pBot);
return; return;
} }
@ -6964,6 +6990,7 @@ void BotFollowPath(AvHAIPlayer* pBot)
MoveToWithoutNav(pBot, CurrentNode.Location); MoveToWithoutNav(pBot, CurrentNode.Location);
pBot->BotNavInfo.StuckInfo.bPathFollowFailed = true; pBot->BotNavInfo.StuckInfo.bPathFollowFailed = true;
ClearBotPath(pBot); ClearBotPath(pBot);
NAV_ClearMovementTask(pBot);
return; return;
} }
@ -7408,6 +7435,7 @@ void ClearBotStuck(AvHAIPlayer* pBot)
bool BotRecalcPath(AvHAIPlayer* pBot, const Vector Destination) bool BotRecalcPath(AvHAIPlayer* pBot, const Vector Destination)
{ {
ClearBotPath(pBot); ClearBotPath(pBot);
NAV_ClearMovementTask(pBot);
Vector ValidNavmeshPoint = UTIL_ProjectPointToNavmesh(Destination, Vector(max_ai_use_reach, max_ai_use_reach, max_ai_use_reach), pBot->BotNavInfo.NavProfile); Vector ValidNavmeshPoint = UTIL_ProjectPointToNavmesh(Destination, Vector(max_ai_use_reach, max_ai_use_reach, max_ai_use_reach), pBot->BotNavInfo.NavProfile);
@ -8772,6 +8800,18 @@ void UTIL_PopulateDoors()
NavDoors.push_back(NewDoor); NavDoors.push_back(NewDoor);
} }
for (auto it = BaseMapConnections.begin(); it != BaseMapConnections.end(); it++)
{
if (!(it->ConnectionFlags & SAMPLE_POLYFLAGS_LIFT)) { continue; }
nav_door* CorrespondingLift = UTIL_GetClosestLiftToPoints(it->FromLocation, it->ToLocation);
if (CorrespondingLift)
{
it->TargetObject = CorrespondingLift->DoorEdict;
}
}
UTIL_UpdateDoors(true); UTIL_UpdateDoors(true);
} }
@ -8790,6 +8830,28 @@ nav_door* UTIL_GetNavDoorByEdict(const edict_t* DoorEdict)
return nullptr; return nullptr;
} }
nav_door* UTIL_GetLiftReferenceByEdict(const edict_t* DoorEdict)
{
if (FNullEnt(DoorEdict)) { return nullptr; }
for (auto it = NavDoors.begin(); it != NavDoors.end(); it++)
{
if (it->DoorEdict == DoorEdict)
{
if (UTIL_GetOffMeshConnectionForLift(&(*it)) != nullptr)
{
return &(*it);
}
else
{
return nullptr;
}
}
}
return nullptr;
}
AvHAIOffMeshConnection* UTIL_GetOffMeshConnectionForLift(nav_door* LiftRef) AvHAIOffMeshConnection* UTIL_GetOffMeshConnectionForLift(nav_door* LiftRef)
{ {
if (!LiftRef) { return nullptr; } if (!LiftRef) { return nullptr; }
@ -8801,15 +8863,20 @@ AvHAIOffMeshConnection* UTIL_GetOffMeshConnectionForLift(nav_door* LiftRef)
{ {
if (!(it->ConnectionFlags & SAMPLE_POLYFLAGS_LIFT)) { continue; } if (!(it->ConnectionFlags & SAMPLE_POLYFLAGS_LIFT)) { continue; }
Vector LiftLocation = UTIL_GetCentreOfEntity(LiftRef->DoorEdict); if (it->TargetObject == LiftRef->DoorEdict)
float ThisDist = fminf(vDist3DSq(it->FromLocation, LiftLocation), vDist3DSq(it->ToLocation, LiftLocation));
if (!NearestConnection || ThisDist < MinDist)
{ {
NearestConnection = &(*it); return &(*it);
MinDist = ThisDist;
} }
//Vector LiftLocation = UTIL_GetCentreOfEntity(LiftRef->DoorEdict);
//float ThisDist = fminf(vDist3DSq(it->FromLocation, LiftLocation), vDist3DSq(it->ToLocation, LiftLocation));
//if (!NearestConnection || ThisDist < MinDist)
//{
// NearestConnection = &(*it);
// MinDist = ThisDist;
//}
} }
return NearestConnection; return NearestConnection;

View File

@ -482,6 +482,7 @@ void UTIL_PopulateWeldableObstacles();
void UTIL_ApplyTempObstaclesToDoor(nav_door* DoorRef, const int Area); void UTIL_ApplyTempObstaclesToDoor(nav_door* DoorRef, const int Area);
nav_door* UTIL_GetLiftReferenceByEdict(const edict_t* DoorEdict);
nav_door* UTIL_GetNavDoorByEdict(const edict_t* DoorEdict); nav_door* UTIL_GetNavDoorByEdict(const edict_t* DoorEdict);
nav_door* UTIL_GetClosestLiftToPoints(const Vector StartPoint, const Vector EndPoint); nav_door* UTIL_GetClosestLiftToPoints(const Vector StartPoint, const Vector EndPoint);
AvHAIOffMeshConnection* UTIL_GetOffMeshConnectionForLift(nav_door* LiftRef); AvHAIOffMeshConnection* UTIL_GetOffMeshConnectionForLift(nav_door* LiftRef);

View File

@ -1353,6 +1353,9 @@ void BotUpdateView(AvHAIPlayer* pBot)
UpdateAIPlayerViewFrustum(pBot); UpdateAIPlayerViewFrustum(pBot);
float ViewUpdateDelta = gpGlobals->time - pBot->LastViewUpdateTime;
ViewUpdateDelta = clampf(ViewUpdateDelta, 0.0f, 0.2f);
// Update list of currently visible players // Update list of currently visible players
for (int i = 1; i <= gpGlobals->maxClients; i++) for (int i = 1; i <= gpGlobals->maxClients; i++)
{ {
@ -1378,6 +1381,10 @@ void BotUpdateView(AvHAIPlayer* pBot)
enemy_status* TrackingInfo = &pBot->TrackedEnemies[EnemyIndex]; enemy_status* TrackingInfo = &pBot->TrackedEnemies[EnemyIndex];
TrackingInfo->CertaintyOfLocation -= (ViewUpdateDelta * 0.15f);
TrackingInfo->CertaintyOfLocation = clampf(TrackingInfo->CertaintyOfLocation, 0.0f, 1.0f);
if (gpGlobals->time < TrackingInfo->NextUpdateTime) if (gpGlobals->time < TrackingInfo->NextUpdateTime)
{ {
continue; continue;
@ -1434,6 +1441,7 @@ void BotUpdateView(AvHAIPlayer* pBot)
if (bInFOV && (bCanSeeEnemy || bIsTracked)) if (bInFOV && (bCanSeeEnemy || bIsTracked))
{ {
TrackingInfo->CertaintyOfLocation = 1.0f;
Vector FloorLocation = UTIL_GetEntityGroundLocation(Enemy); Vector FloorLocation = UTIL_GetEntityGroundLocation(Enemy);
Vector BotVelocity = Enemy->v.velocity; Vector BotVelocity = Enemy->v.velocity;
@ -1486,7 +1494,7 @@ void BotUpdateView(AvHAIPlayer* pBot)
} }
} }
if (bHasLOS) if (bHasLOS && bCanSeeEnemy)
{ {
TrackingInfo->LastLOSPosition = pBot->CurrentFloorPosition + Vector(0.0f, 0.0f, 5.0f); TrackingInfo->LastLOSPosition = pBot->CurrentFloorPosition + Vector(0.0f, 0.0f, 5.0f);
@ -1554,6 +1562,8 @@ void BotUpdateView(AvHAIPlayer* pBot)
{ {
pBot->LastSafeLocation = pBot->Edict->v.origin; pBot->LastSafeLocation = pBot->Edict->v.origin;
} }
} }
bool UTIL_IsCloakedPlayerInvisible(edict_t* Observer, AvHPlayer* Player) bool UTIL_IsCloakedPlayerInvisible(edict_t* Observer, AvHPlayer* Player)
@ -1595,6 +1605,7 @@ void BotClearEnemyTrackingInfo(enemy_status* TrackingInfo)
TrackingInfo->LastSeenTime = 0.0f; TrackingInfo->LastSeenTime = 0.0f;
TrackingInfo->LastLOSPosition = ZERO_VECTOR; TrackingInfo->LastLOSPosition = ZERO_VECTOR;
TrackingInfo->LastHiddenPosition = ZERO_VECTOR; TrackingInfo->LastHiddenPosition = ZERO_VECTOR;
TrackingInfo->CertaintyOfLocation = 0.0f;
} }
void UpdateAIPlayerViewFrustum(AvHAIPlayer* pBot) void UpdateAIPlayerViewFrustum(AvHAIPlayer* pBot)
@ -1895,23 +1906,25 @@ void EndBotFrame(AvHAIPlayer* pBot)
void CustomThink(AvHAIPlayer* pBot) void CustomThink(AvHAIPlayer* pBot)
{ {
if (IsPlayerMarine(pBot->Edict)) { return; }
if (!PlayerHasAlienUpgradeOfType(pBot->Edict, HIVE_TECH_SENSORY))
{
BotEvolveUpgrade(pBot, pBot->CurrentFloorPosition, ALIEN_EVOLUTION_TEN);
return;
}
pBot->CurrentEnemy = BotGetNextEnemyTarget(pBot); pBot->CurrentEnemy = BotGetNextEnemyTarget(pBot);
if (pBot->CurrentEnemy < 0) if (pBot->CurrentEnemy >= 0)
{ {
MoveTo(pBot, AITAC_GetTeamStartingLocation(AIMGR_GetEnemyTeam(pBot->Player->GetTeam())), MOVESTYLE_NORMAL); enemy_status* TrackingInfo = &pBot->TrackedEnemies[pBot->CurrentEnemy];
}
else char msg[32];
{ sprintf(msg, "%.2f\n", TrackingInfo->CertaintyOfLocation);
AlienCombatThink(pBot); UTIL_SayText(msg, CBaseEntity::Instance(INDEXENT(1)));
if (IsPlayerMarine(pBot->Edict))
{
MarineCombatThink(pBot);
}
else
{
AlienCombatThink(pBot);
}
} }
} }
@ -2005,11 +2018,41 @@ void UpdateAIPlayerDMRole(AvHAIPlayer* pBot)
} }
void AIPlayerHearEnemy(AvHAIPlayer* pBot, edict_t* HeardEnemy, float SoundVolume)
{
int heardIndex = ENTINDEX(HeardEnemy) - 1;
if (heardIndex < 0 || heardIndex >= 32 || HeardEnemy->v.team == pBot->Edict->v.team) { return; }
enemy_status* HeardEnemyStatus = &pBot->TrackedEnemies[heardIndex];
HeardEnemyStatus->LastSeenTime = gpGlobals->time;
HeardEnemyStatus->CertaintyOfLocation += SoundVolume;
HeardEnemyStatus->CertaintyOfLocation = clampf(HeardEnemyStatus->CertaintyOfLocation, 0.0f, 1.0f);
if (HeardEnemyStatus->CertaintyOfLocation < 0.15f) { return; }
// If the bot can't see the enemy (bCurrentlyVisible is false) then set the last seen location to a random point in the vicinity so the bot doesn't immediately know where they are
if (HeardEnemyStatus->bIsVisible || HeardEnemyStatus->CertaintyOfLocation > 0.75f || vDist2DSq(HeardEnemyStatus->EnemyEdict->v.origin, pBot->Edict->v.origin) < sqrf(UTIL_MetresToGoldSrcUnits(3.0f)))
{
HeardEnemyStatus->LastSeenLocation = HeardEnemy->v.origin;
}
else
{
// The further the enemy is, the more inaccurate the bot's guess will be where they are
HeardEnemyStatus->LastSeenLocation = UTIL_GetRandomPointOnNavmeshInRadius(GetBaseNavProfile(SKULK_BASE_NAV_PROFILE), HeardEnemy->v.origin, UTIL_MetresToGoldSrcUnits(5.0f));
}
HeardEnemyStatus->bIsAwareOfPlayer = true;
}
void AIPlayerTakeDamage(AvHAIPlayer* pBot, int damageTaken, edict_t* aggressor) void AIPlayerTakeDamage(AvHAIPlayer* pBot, int damageTaken, edict_t* aggressor)
{ {
int aggressorIndex = ENTINDEX(aggressor) - 1; int aggressorIndex = ENTINDEX(aggressor) - 1;
if (aggressorIndex > -1 && aggressor->v.team != pBot->Edict->v.team && IsPlayerActiveInGame(aggressor)) if (aggressorIndex < 0 || aggressorIndex >= 32) { return; }
if (aggressor->v.team != pBot->Edict->v.team && IsPlayerActiveInGame(aggressor))
{ {
pBot->TrackedEnemies[aggressorIndex].LastSeenTime = gpGlobals->time; pBot->TrackedEnemies[aggressorIndex].LastSeenTime = gpGlobals->time;
@ -2575,7 +2618,7 @@ AvHAICombatStrategy GetFadeCombatStrategyForTarget(AvHAIPlayer* pBot, enemy_stat
{ {
if (DistToEnemy > sqrf(UTIL_MetresToGoldSrcUnits(5.0f))) if (DistToEnemy > sqrf(UTIL_MetresToGoldSrcUnits(5.0f)))
{ {
if ((bEnemyHasDeadlyWeapon && (FacingDot > 0.5f || NumAllies > 0)) || NumAllies > 2) if ((bEnemyHasDeadlyWeapon && (FacingDot > 0.5f || NumAllies > 0)) || NumAllies > 1)
{ {
return COMBAT_STRATEGY_SKIRMISH; return COMBAT_STRATEGY_SKIRMISH;
} }
@ -2583,7 +2626,7 @@ AvHAICombatStrategy GetFadeCombatStrategyForTarget(AvHAIPlayer* pBot, enemy_stat
} }
else else
{ {
if ((bEnemyHasDeadlyWeapon && (FacingDot > 0.5f || NumAllies > 0)) || NumAllies > 2) if ((bEnemyHasDeadlyWeapon && (FacingDot > 0.5f || NumAllies > 0)) || NumAllies > 1)
{ {
Vector EnemyVelocity = UTIL_GetVectorNormal2D(CurrentEnemy->LastSeenVelocity); Vector EnemyVelocity = UTIL_GetVectorNormal2D(CurrentEnemy->LastSeenVelocity);
@ -2683,7 +2726,7 @@ AvHAICombatStrategy GetMarineCombatStrategyForTarget(AvHAIPlayer* pBot, enemy_st
float DistToEnemy = vDist2DSq(pBot->Edict->v.origin, CurrentEnemy->LastSeenLocation); float DistToEnemy = vDist2DSq(pBot->Edict->v.origin, CurrentEnemy->LastSeenLocation);
bool bCanRetreat = AITAC_IsCompletedStructureOfTypeNearLocation(BotTeam, (STRUCTURE_MARINE_COMMCHAIR | STRUCTURE_MARINE_ARMOURY | STRUCTURE_MARINE_ADVARMOURY), ZERO_VECTOR, 0.0f); bool bCanRetreat = AITAC_IsCompletedStructureOfTypeNearLocation(BotTeam, (STRUCTURE_MARINE_ARMOURY | STRUCTURE_MARINE_ADVARMOURY), ZERO_VECTOR, 0.0f);
// If we are doing something important, don't get distracted by enemies that aren't an immediate threat // If we are doing something important, don't get distracted by enemies that aren't an immediate threat
if (pBot->CurrentTask && (pBot->CurrentTask->TaskType == TASK_DEFEND || pBot->CommanderTask.TaskType != TASK_NONE)) if (pBot->CurrentTask && (pBot->CurrentTask->TaskType == TASK_DEFEND || pBot->CommanderTask.TaskType != TASK_NONE))
@ -2712,6 +2755,11 @@ AvHAICombatStrategy GetMarineCombatStrategyForTarget(AvHAIPlayer* pBot, enemy_st
return COMBAT_STRATEGY_RETREAT; return COMBAT_STRATEGY_RETREAT;
} }
if (UTIL_GetPlayerPrimaryWeaponClipAmmo(pBot->Player) == 0 && UTIL_GetPlayerPrimaryAmmoReserve(pBot->Player) == 0 && UTIL_GetPlayerSecondaryWeaponClipAmmo(pBot->Player) == 0 && UTIL_GetPlayerSecondaryAmmoReserve(pBot->Player) == 0)
{
return COMBAT_STRATEGY_ATTACK;
}
// Shotty users should attack, can't really skirmish with a shotgun // Shotty users should attack, can't really skirmish with a shotgun
if (PlayerHasWeapon(pBot->Player, WEAPON_MARINE_SHOTGUN) && (UTIL_GetPlayerPrimaryAmmoReserve(pBot->Player) > 0 || UTIL_GetPlayerPrimaryWeaponClipAmmo(pBot->Player) > 0)) if (PlayerHasWeapon(pBot->Player, WEAPON_MARINE_SHOTGUN) && (UTIL_GetPlayerPrimaryAmmoReserve(pBot->Player) > 0 || UTIL_GetPlayerPrimaryWeaponClipAmmo(pBot->Player) > 0))
{ {
@ -2899,6 +2947,7 @@ void BotThrowGrenadeAtTarget(AvHAIPlayer* pBot, const Vector TargetPoint)
BotShootLocation(pBot, GetPlayerCurrentWeapon(pBot->Player), ThrowTargetLocation); BotShootLocation(pBot, GetPlayerCurrentWeapon(pBot->Player), ThrowTargetLocation);
} }
bool BombardierCombatThink(AvHAIPlayer* pBot) bool BombardierCombatThink(AvHAIPlayer* pBot)
{ {
return false; return false;
@ -2921,11 +2970,12 @@ bool RegularMarineCombatThink(AvHAIPlayer* pBot)
bool bBotIsGrenadier = (DesiredCombatWeapon == WEAPON_MARINE_GL); bool bBotIsGrenadier = (DesiredCombatWeapon == WEAPON_MARINE_GL);
float DistToEnemy = vDist2DSq(pBot->Edict->v.origin, CurrentEnemy->v.origin); float DistToEnemy = vDist2DSq(pBot->Edict->v.origin, TrackedEnemyRef->LastSeenLocation);
bool bEnemyIsRanged = IsPlayerMarine(TrackedEnemyRef->EnemyPlayer) || ((GetPlayerCurrentWeapon(TrackedEnemyRef->EnemyPlayer) == WEAPON_FADE_ACIDROCKET) && DistToEnemy > sqrf(UTIL_MetresToGoldSrcUnits(5.0f))); bool bEnemyIsRanged = IsPlayerMarine(TrackedEnemyRef->EnemyPlayer) || ((GetPlayerCurrentWeapon(TrackedEnemyRef->EnemyPlayer) == WEAPON_FADE_ACIDROCKET) && DistToEnemy > sqrf(UTIL_MetresToGoldSrcUnits(5.0f)));
float LastEnemySeenTime = (TrackedEnemyRef->LastTrackedTime > 0.0f) ? TrackedEnemyRef->LastTrackedTime : TrackedEnemyRef->LastSeenTime; float LastEnemySeenTime = (TrackedEnemyRef->LastTrackedTime > 0.0f) ? TrackedEnemyRef->LastTrackedTime : TrackedEnemyRef->LastSeenTime;
float TimeSinceLastEnemySighting = gpGlobals->time - LastEnemySeenTime;
Vector LastEnemySeenLocation = TrackedEnemyRef->LastSeenLocation; Vector LastEnemySeenLocation = TrackedEnemyRef->LastSeenLocation;
// Run away and restock // Run away and restock
@ -3017,15 +3067,29 @@ bool RegularMarineCombatThink(AvHAIPlayer* pBot)
// Maintain distance, pop and shoot // Maintain distance, pop and shoot
if (pBot->CurrentCombatStrategy == COMBAT_STRATEGY_SKIRMISH || pBot->CurrentCombatStrategy == COMBAT_STRATEGY_AMBUSH) if (pBot->CurrentCombatStrategy == COMBAT_STRATEGY_SKIRMISH || pBot->CurrentCombatStrategy == COMBAT_STRATEGY_AMBUSH)
{ {
pBot->DesiredCombatWeapon = DesiredCombatWeapon;
if (GetPlayerCurrentWeapon(pBot->Player) != DesiredCombatWeapon)
{
return true;
}
if (vIsZero(pBot->LastSafeLocation)) if (vIsZero(pBot->LastSafeLocation))
{ {
pBot->LastSafeLocation = AITAC_GetTeamStartingLocation(BotTeam); pBot->LastSafeLocation = AITAC_GetTeamStartingLocation(BotTeam);
} }
if (TrackedEnemyRef->bHasLOS) float DesiredDistance = GetMinIdealWeaponRange(DesiredCombatWeapon) + ((GetMaxIdealWeaponRange(DesiredCombatWeapon) - GetMinIdealWeaponRange(DesiredCombatWeapon)) * 0.5f);
bool bCanReloadCurrentWeapon = (WeaponCanBeReloaded(DesiredCombatWeapon) && GetPlayerCurrentWeaponClipAmmo(pBot->Player) < GetPlayerCurrentWeaponMaxClipAmmo(pBot->Player) && GetPlayerCurrentWeaponReserveAmmo(pBot->Player) > 0);
bool bMustReloadCurrentWeapon = bCanReloadCurrentWeapon && GetPlayerCurrentWeaponClipAmmo(pBot->Player) == 0;
bool bCanReloadAnyWeapon = BotAnyWeaponNeedsReloading(pBot);
if (TrackedEnemyRef->bHasLOS && (TrackedEnemyRef->bIsVisible || TrackedEnemyRef->CertaintyOfLocation >= 0.8f))
{ {
if (GetPlayerCurrentWeaponClipAmmo(pBot->Player) == 0) if (bMustReloadCurrentWeapon)
{ {
BotLookAt(pBot, TrackedEnemyRef->LastSeenLocation);
MoveTo(pBot, pBot->LastSafeLocation, MOVESTYLE_NORMAL); MoveTo(pBot, pBot->LastSafeLocation, MOVESTYLE_NORMAL);
BotReloadWeapons(pBot); BotReloadWeapons(pBot);
return true; return true;
@ -3033,7 +3097,9 @@ bool RegularMarineCombatThink(AvHAIPlayer* pBot)
if (vDist2DSq(pBot->Edict->v.origin, pBot->LastSafeLocation) > sqrf(UTIL_MetresToGoldSrcUnits(3.0f))) if (vDist2DSq(pBot->Edict->v.origin, pBot->LastSafeLocation) > sqrf(UTIL_MetresToGoldSrcUnits(3.0f)))
{ {
BotLookAt(pBot, TrackedEnemyRef->LastSeenLocation);
MoveTo(pBot, pBot->LastSafeLocation, MOVESTYLE_NORMAL); MoveTo(pBot, pBot->LastSafeLocation, MOVESTYLE_NORMAL);
} }
else else
{ {
@ -3099,6 +3165,7 @@ bool RegularMarineCombatThink(AvHAIPlayer* pBot)
if (BotReloadWeapons(pBot)) { return true; } if (BotReloadWeapons(pBot)) { return true; }
BotLookAt(pBot, LastEnemySeenLocation);
MoveTo(pBot, LastEnemySeenLocation, MOVESTYLE_NORMAL); MoveTo(pBot, LastEnemySeenLocation, MOVESTYLE_NORMAL);
} }
@ -3108,19 +3175,43 @@ bool RegularMarineCombatThink(AvHAIPlayer* pBot)
// Go for the kill. Maintain desired distance and pursue when needed // Go for the kill. Maintain desired distance and pursue when needed
if (pBot->CurrentCombatStrategy == COMBAT_STRATEGY_ATTACK) if (pBot->CurrentCombatStrategy == COMBAT_STRATEGY_ATTACK)
{ {
AvHAIWeapon IdealAttackWeapon = (UTIL_GetPlayerPrimaryAmmoReserve(pBot->Player) > 0 || UTIL_GetPlayerPrimaryWeaponClipAmmo(pBot->Player) > 0) ? UTIL_GetPlayerPrimaryWeapon(pBot->Player) : DesiredCombatWeapon; pBot->DesiredCombatWeapon = DesiredCombatWeapon;
float DesiredDistance = GetMinIdealWeaponRange(IdealAttackWeapon) + ((GetMaxIdealWeaponRange(IdealAttackWeapon) - GetMinIdealWeaponRange(IdealAttackWeapon)) * 0.5f); if (GetPlayerCurrentWeapon(pBot->Player) != DesiredCombatWeapon)
{
bool bCanReloadCurrentWeapon = (WeaponCanBeReloaded(DesiredCombatWeapon) && GetPlayerCurrentWeaponClipAmmo(pBot->Player) < GetPlayerCurrentWeaponMaxClipAmmo(pBot->Player) && GetPlayerCurrentWeaponReserveAmmo(pBot->Player) > 0); return true;
bool bMustReloadCurrentWeapon = bCanReloadCurrentWeapon && GetPlayerCurrentWeaponClipAmmo(pBot->Player) == 0; }
if (vIsZero(pBot->LastSafeLocation)) if (vIsZero(pBot->LastSafeLocation))
{ {
pBot->LastSafeLocation = AITAC_GetTeamStartingLocation(BotTeam); pBot->LastSafeLocation = AITAC_GetTeamStartingLocation(BotTeam);
} }
if (!TrackedEnemyRef->bHasLOS) float DesiredDistance = GetMinIdealWeaponRange(DesiredCombatWeapon) + ((GetMaxIdealWeaponRange(DesiredCombatWeapon) - GetMinIdealWeaponRange(DesiredCombatWeapon)) * 0.5f);
bool bCanReloadCurrentWeapon = (WeaponCanBeReloaded(DesiredCombatWeapon) && GetPlayerCurrentWeaponClipAmmo(pBot->Player) < GetPlayerCurrentWeaponMaxClipAmmo(pBot->Player) && GetPlayerCurrentWeaponReserveAmmo(pBot->Player) > 0);
bool bMustReloadCurrentWeapon = bCanReloadCurrentWeapon && GetPlayerCurrentWeaponClipAmmo(pBot->Player) == 0;
bool bCanReloadAnyWeapon = BotAnyWeaponNeedsReloading(pBot);
if (bMustReloadCurrentWeapon)
{
BotReloadWeapons(pBot);
BotLookAt(pBot, TrackedEnemyRef->LastSeenLocation);
if (TrackedEnemyRef->bHasLOS || DistToEnemy < sqrf(UTIL_MetresToGoldSrcUnits(5.0f)))
{
MoveTo(pBot, pBot->LastSafeLocation, MOVESTYLE_NORMAL);
}
else
{
BotGuardLocation(pBot, pBot->Edict->v.origin);
}
return true;
}
if (!TrackedEnemyRef->bHasLOS || (!TrackedEnemyRef->bIsVisible && TrackedEnemyRef->CertaintyOfLocation < 0.8f))
{ {
if (PlayerHasWeapon(pBot->Player, WEAPON_MARINE_GRENADE) || (PlayerHasWeapon(pBot->Player, WEAPON_MARINE_GL) && UTIL_GetPlayerPrimaryWeaponClipAmmo(pBot->Player) > 0)) if (PlayerHasWeapon(pBot->Player, WEAPON_MARINE_GRENADE) || (PlayerHasWeapon(pBot->Player, WEAPON_MARINE_GL) && UTIL_GetPlayerPrimaryWeaponClipAmmo(pBot->Player) > 0))
{ {
@ -3133,103 +3224,100 @@ bool RegularMarineCombatThink(AvHAIPlayer* pBot)
} }
} }
if ((IdealAttackWeapon != DesiredCombatWeapon || bCanReloadCurrentWeapon) && gpGlobals->time - TrackedEnemyRef->LastSeenTime > 3.0f) if (bCanReloadAnyWeapon && gpGlobals->time - TrackedEnemyRef->LastSeenTime > 3.0f)
{ {
BotReloadWeapons(pBot); BotReloadWeapons(pBot);
if (vDist2DSq(pBot->Edict->v.origin, TrackedEnemyRef->LastVisibleLocation) < sqrf(UTIL_MetresToGoldSrcUnits(5.0f))) BotLookAt(pBot, TrackedEnemyRef->LastSeenLocation);
{
if (DistToEnemy < sqrf(UTIL_MetresToGoldSrcUnits(5.0f)))
{
MoveTo(pBot, AITAC_GetTeamStartingLocation(BotTeam), MOVESTYLE_NORMAL); MoveTo(pBot, AITAC_GetTeamStartingLocation(BotTeam), MOVESTYLE_NORMAL);
} }
return true; return true;
} }
MoveTo(pBot, TrackedEnemyRef->LastSeenLocation, MOVESTYLE_NORMAL); BotGuardLocation(pBot, LastEnemySeenLocation);
return true; return true;
} }
if (bCanReloadCurrentWeapon && DistToEnemy > sqrf(DesiredDistance))
{
BotReloadWeapons(pBot);
}
BotAttackResult LOSCheck = PerformAttackLOSCheck(pBot, DesiredCombatWeapon, CurrentEnemy); BotAttackResult LOSCheck = PerformAttackLOSCheck(pBot, DesiredCombatWeapon, CurrentEnemy);
if (bMustReloadCurrentWeapon) if (LOSCheck != ATTACK_SUCCESS)
{ {
MoveTo(pBot, pBot->LastSafeLocation, MOVESTYLE_NORMAL); MoveTo(pBot, TrackedEnemyRef->LastSeenLocation, MOVESTYLE_NORMAL);
BotReloadWeapons(pBot);
return true; return true;
} }
if (DistToEnemy > sqrf(DesiredDistance)) if (bEnemyIsRanged)
{ {
if (IdealAttackWeapon != DesiredCombatWeapon) Vector EnemyOrientation = UTIL_GetVectorNormal2D(CurrentEnemy->v.origin - pBot->Edict->v.origin);
Vector RightDir = UTIL_GetCrossProduct(EnemyOrientation, UP_VECTOR);
pBot->desiredMovementDir = (pBot->BotNavInfo.bZig) ? UTIL_GetVectorNormal2D(RightDir) : UTIL_GetVectorNormal2D(-RightDir);
// Let's get ziggy with it
if (gpGlobals->time > pBot->BotNavInfo.NextZigTime)
{ {
BotReloadWeapons(pBot); pBot->BotNavInfo.bZig = !pBot->BotNavInfo.bZig;
MoveTo(pBot, pBot->LastSafeLocation, MOVESTYLE_NORMAL); pBot->BotNavInfo.NextZigTime = gpGlobals->time + frandrange(0.5f, 1.0f);
return true;
} }
MoveTo(pBot, LastEnemySeenLocation, MOVESTYLE_NORMAL); BotMovementInputs(pBot);
} }
else else
{ {
if (bEnemyIsRanged) float MinDesiredDist = GetMinIdealWeaponRange(DesiredCombatWeapon);
Vector Orientation = UTIL_GetVectorNormal2D(CurrentEnemy->v.origin - pBot->Edict->v.origin);
float EnemyMoveDot = UTIL_GetDotProduct2D(UTIL_GetVectorNormal2D(CurrentEnemy->v.velocity), -Orientation);
// Enemy is too close for comfort, or is moving towards us. Back up
if (DistToEnemy < MinDesiredDist || EnemyMoveDot > 0.7f)
{ {
Vector EnemyOrientation = UTIL_GetVectorNormal2D(CurrentEnemy->v.origin - pBot->Edict->v.origin); Vector RetreatLocation = pBot->CurrentFloorPosition - (Orientation * 50.0f);
Vector RightDir = UTIL_GetCrossProduct(EnemyOrientation, UP_VECTOR); if (UTIL_PointIsDirectlyReachable(pBot->CurrentFloorPosition, RetreatLocation))
pBot->desiredMovementDir = (pBot->BotNavInfo.bZig) ? UTIL_GetVectorNormal2D(RightDir) : UTIL_GetVectorNormal2D(-RightDir);
// Let's get ziggy with it
if (gpGlobals->time > pBot->BotNavInfo.NextZigTime)
{ {
pBot->BotNavInfo.bZig = !pBot->BotNavInfo.bZig; MoveDirectlyTo(pBot, RetreatLocation);
pBot->BotNavInfo.NextZigTime = gpGlobals->time + frandrange(0.5f, 1.0f); }
if (DesiredCombatWeapon != WEAPON_MARINE_KNIFE)
{
if (DistToEnemy < sqrf(100.0f))
{
if (IsPlayerReloading(pBot->Player) && CanInterruptWeaponReload(GetPlayerCurrentWeapon(pBot->Player)) && GetPlayerCurrentWeaponClipAmmo(pBot->Player) > 0)
{
InterruptReload(pBot);
return true;
}
BotJump(pBot);
}
} }
BotMovementInputs(pBot);
} }
else else
{ {
if (!UTIL_PlayerHasLOSToLocation(pBot->Edict, TrackedEnemyRef->LastSeenLocation, UTIL_MetresToGoldSrcUnits(5.0f)))
float MinDesiredDist = GetMinIdealWeaponRange(DesiredCombatWeapon);
Vector Orientation = UTIL_GetVectorNormal2D(CurrentEnemy->v.origin - pBot->Edict->v.origin);
float EnemyMoveDot = UTIL_GetDotProduct2D(UTIL_GetVectorNormal2D(CurrentEnemy->v.velocity), -Orientation);
// Enemy is too close for comfort, or is moving towards us. Back up
if (DistToEnemy < MinDesiredDist || EnemyMoveDot > 0.7f)
{
Vector RetreatLocation = pBot->CurrentFloorPosition - (Orientation * 50.0f);
if (UTIL_PointIsDirectlyReachable(pBot->CurrentFloorPosition, RetreatLocation))
{
MoveDirectlyTo(pBot, RetreatLocation);
}
if (DesiredCombatWeapon != WEAPON_MARINE_KNIFE)
{
if (DistToEnemy < sqrf(100.0f))
{
if (IsPlayerReloading(pBot->Player) && CanInterruptWeaponReload(GetPlayerCurrentWeapon(pBot->Player)) && GetPlayerCurrentWeaponClipAmmo(pBot->Player) > 0)
{
InterruptReload(pBot);
return true;
}
BotJump(pBot);
}
}
}
else
{ {
MoveTo(pBot, TrackedEnemyRef->LastSeenLocation, MOVESTYLE_NORMAL); MoveTo(pBot, TrackedEnemyRef->LastSeenLocation, MOVESTYLE_NORMAL);
} }
else
{
BotGuardLocation(pBot, TrackedEnemyRef->LastSeenLocation);
}
} }
BotShootTarget(pBot, DesiredCombatWeapon, CurrentEnemy);
} }
BotShootTarget(pBot, DesiredCombatWeapon, CurrentEnemy);
return true; return true;
} }

View File

@ -153,6 +153,7 @@ void UpdateAIPlayerDMRole(AvHAIPlayer* pBot);
bool ShouldAIPlayerTakeCommand(AvHAIPlayer* pBot); bool ShouldAIPlayerTakeCommand(AvHAIPlayer* pBot);
void AIPlayerTakeDamage(AvHAIPlayer* pBot, int damageTaken, edict_t* aggressor); void AIPlayerTakeDamage(AvHAIPlayer* pBot, int damageTaken, edict_t* aggressor);
void AIPlayerHearEnemy(AvHAIPlayer* pBot, edict_t* HeardEnemy, float SoundVolume);
int BotGetNextEnemyTarget(AvHAIPlayer* pBot); int BotGetNextEnemyTarget(AvHAIPlayer* pBot);

View File

@ -8,6 +8,7 @@
#include "AvHAIHelper.h" #include "AvHAIHelper.h"
#include "AvHAICommander.h" #include "AvHAICommander.h"
#include "AvHAIPlayerUtil.h" #include "AvHAIPlayerUtil.h"
#include "AvHAISoundQueue.h"
#include "AvHGamerules.h" #include "AvHGamerules.h"
#include "../dlls/client.h" #include "../dlls/client.h"
#include <time.h> #include <time.h>
@ -51,6 +52,8 @@ float CountdownStartedTime = 0.0f;
bool bBotsEnabled = false; bool bBotsEnabled = false;
float CurrentFrameDelta = 0.01f;
AvHAICommanderMode AIMGR_GetCommanderMode() AvHAICommanderMode AIMGR_GetCommanderMode()
{ {
if (avh_botcommandermode.value == 1) if (avh_botcommandermode.value == 1)
@ -560,6 +563,8 @@ void AIMGR_UpdateAIPlayers()
float FrameDelta = CurrTime - PrevTime; float FrameDelta = CurrTime - PrevTime;
AIMGR_SetFrameDelta(FrameDelta);
int cvarBotSkill = clampi((int)avh_botskill.value, 0, 3); int cvarBotSkill = clampi((int)avh_botskill.value, 0, 3);
bool bSkillChanged = (cvarBotSkill != CurrentBotSkill); bool bSkillChanged = (cvarBotSkill != CurrentBotSkill);
@ -592,6 +597,8 @@ void AIMGR_UpdateAIPlayers()
AIMGR_SetCommanderAllowedTime(TeamBNumber, gpGlobals->time + 15.0f); AIMGR_SetCommanderAllowedTime(TeamBNumber, gpGlobals->time + 15.0f);
} }
} }
AIMGR_ProcessPendingSounds();
} }
int NumCommanders = AIMGR_GetNumAICommanders(); int NumCommanders = AIMGR_GetNumAICommanders();
@ -709,7 +716,7 @@ AvHTeamNumber AIMGR_GetTeamANumber()
AvHTeamNumber AIMGR_GetTeamBNumber() AvHTeamNumber AIMGR_GetTeamBNumber()
{ {
return GetGameRules()->GetTeamANumber(); return GetGameRules()->GetTeamBNumber();
} }
AvHTeam* AIMGR_GetTeamRef(const AvHTeamNumber Team) AvHTeam* AIMGR_GetTeamRef(const AvHTeamNumber Team)
@ -1450,4 +1457,100 @@ bool AIMGR_IsMatchPracticallyOver()
} }
return false; return false;
}
void AIMGR_ProcessPendingSounds()
{
float FrameDelta = AIMGR_GetFrameDelta();
for (auto it = ActiveAIPlayers.begin(); it != ActiveAIPlayers.end(); it++)
{
it->HearingThreshold -= FrameDelta;
it->HearingThreshold = clampf(it->HearingThreshold, 0.0f, 1.0f);
}
AvHAISound Sound = AISND_PopSound();
AvHTeamNumber TeamANumber = AIMGR_GetTeamANumber();
AvHTeamNumber TeamBNumber = AIMGR_GetTeamBNumber();
while (Sound.SoundType != AI_SOUND_NONE)
{
edict_t* EmittingEntity = INDEXENT(Sound.EntIndex);
//string SoundType = "Unknown";
float MaxDist = 0.0f;
switch (Sound.SoundType)
{
case AI_SOUND_FOOTSTEP:
MaxDist = UTIL_MetresToGoldSrcUnits(20.0f);
//SoundType = "Footstep";
break;
case AI_SOUND_SHOOT:
MaxDist = UTIL_MetresToGoldSrcUnits(30.0f);
//SoundType = "Shoot";
break;
case AI_SOUND_VOICELINE:
MaxDist = UTIL_MetresToGoldSrcUnits(20.0f);
//SoundType = "Voiceline";
break;
case AI_SOUND_LANDING:
MaxDist = UTIL_MetresToGoldSrcUnits(20.0f);
//SoundType = "Landing";
break;
case AI_SOUND_OTHER:
default:
MaxDist = UTIL_MetresToGoldSrcUnits(20.0f);
//SoundType = "Other";
break;
}
MaxDist = sqrf(MaxDist);
if (!FNullEnt(EmittingEntity) && EmittingEntity->v.team != 0 && IsEdictPlayer(EmittingEntity) && IsPlayerActiveInGame(EmittingEntity))
{
AvHTeamNumber EmitterTeam = (AvHTeamNumber)EmittingEntity->v.team;
for (auto it = ActiveAIPlayers.begin(); it != ActiveAIPlayers.end(); it++)
{
AvHTeamNumber ThisTeam = it->Player->GetTeam();
float Volume = Sound.Volume;
float HearingThresholdScalar = (ThisTeam != EmitterTeam || EmittingEntity == it->Edict) ? 1.0f : 0.5f;
if (EmitterTeam != ThisTeam)
{
float DistFromSound = vDist3DSq(Sound.SoundLocation, it->Edict->v.origin);
if (DistFromSound > MaxDist) { continue; }
Volume = Sound.Volume - (Sound.Volume * clampf((DistFromSound / MaxDist), 0.0f, 1.0f));
}
Volume = Volume * HearingThresholdScalar;
if (Volume > it->HearingThreshold)
{
it->HearingThreshold = Volume;
if (EmitterTeam != ThisTeam)
{
AIPlayerHearEnemy(&(*it), EmittingEntity, Volume);
}
}
}
}
Sound = AISND_PopSound();
}
}
void AIMGR_SetFrameDelta(float NewValue)
{
CurrentFrameDelta = NewValue;
}
float AIMGR_GetFrameDelta()
{
return CurrentFrameDelta;
} }

View File

@ -126,4 +126,9 @@ bool AIMGR_HasMatchEnded();
bool AIMGR_IsMatchPracticallyOver(); bool AIMGR_IsMatchPracticallyOver();
void AIMGR_ProcessPendingSounds();
void AIMGR_SetFrameDelta(float NewValue);
float AIMGR_GetFrameDelta();
#endif #endif

View File

@ -0,0 +1,35 @@
#include "AvHAISoundQueue.h"
#include "AvHAIPlayerManager.h"
std::vector<AvHAISound> PendingSounds;
void AISND_RegisterNewSound(int EntIndex, float* NewLocation, AvHAISoundType NewSoundType, float Volume)
{
if (!AIMGR_IsBotEnabled() || Volume < 0.01f) { return; }
AvHAISound NewSound;
NewSound.EntIndex = EntIndex;
NewSound.SoundLocation[0] = NewLocation[0];
NewSound.SoundLocation[1] = NewLocation[1];
NewSound.SoundLocation[2] = NewLocation[2];
NewSound.Volume = Volume;
NewSound.SoundType = NewSoundType;
PendingSounds.push_back(NewSound);
}
AvHAISound AISND_PopSound()
{
if (PendingSounds.size() == 0) { return AvHAISound(); }
AvHAISound Result = PendingSounds.back();
PendingSounds.pop_back();
return Result;
}
void AISND_ClearSounds()
{
PendingSounds.clear();
}

View File

@ -0,0 +1,35 @@
#ifndef AVH_AI_SOUND_QUEUE
#define AVH_AI_SOUND_QUEUE
#include <vector>
// Sound types affect how audible they are to bots, how easy it is to pinpoint the location of the sound etc
typedef enum _AVHAISOUNDTYPE
{
AI_SOUND_NONE = 0, // Blank sound
AI_SOUND_FOOTSTEP, // Footstep sound
AI_SOUND_LANDING, // Landing sound, THUD
AI_SOUND_SHOOT, // Pew pew
AI_SOUND_VOICELINE, // Player played a voice line (e.g. "Need a medpack")
AI_SOUND_OTHER // Miscellaneous sound e.g. building
} AvHAISoundType;
typedef struct _AVHAISOUND
{
int EntIndex = 0;
float SoundLocation[3] = {0.0f, 0.0f, 0.0f};
float Volume = 1.0f;
AvHAISoundType SoundType = AI_SOUND_NONE;
} AvHAISound;
void AISND_RegisterNewSound(int EntIndex, float* NewLocation, AvHAISoundType NewSoundType, float Volume = 1.0f);
AvHAISound AISND_PopSound();
void AISND_ClearSounds();
#endif

View File

@ -1931,7 +1931,7 @@ void BotProgressEvolveTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
{ {
if ((gpGlobals->time - Task->TaskStartedTime) > 1.0f) if ((gpGlobals->time - Task->TaskStartedTime) > 1.0f)
{ {
Task->TaskLocation = UTIL_GetRandomPointOnNavmeshInRadiusIgnoreReachability(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), pBot->Edict->v.origin, UTIL_MetresToGoldSrcUnits(5.0f)); Task->TaskLocation = UTIL_GetRandomPointOnNavmeshInRadius(GetBaseNavProfile(STRUCTURE_BASE_NAV_PROFILE), pBot->Edict->v.origin, UTIL_MetresToGoldSrcUnits(5.0f));
if (vIsZero(Task->TaskLocation)) if (vIsZero(Task->TaskLocation))
{ {

View File

@ -562,128 +562,12 @@ AvHAIWeapon BotMarineChooseBestWeapon(AvHAIPlayer* pBot, edict_t* target)
{ {
return GetBotMarineSecondaryWeapon(pBot); return GetBotMarineSecondaryWeapon(pBot);
} }
else return UTIL_GetPlayerPrimaryWeapon(pBot->Player);
{
return UTIL_GetPlayerPrimaryWeapon(pBot->Player);
}
} }
if (IsEdictPlayer(target)) if (IsEdictPlayer(target))
{ {
float DistFromEnemy = vDist2DSq(pBot->Edict->v.origin, target->v.origin); return MarineGetBestWeaponForPlayerTarget(pBot, dynamic_cast<AvHPlayer*>(CBaseEntity::Instance(target)));
if (UTIL_GetPlayerPrimaryWeapon(pBot->Player) == WEAPON_MARINE_GL)
{
if (UTIL_GetPlayerPrimaryWeaponClipAmmo(pBot->Player) > 0 && DistFromEnemy > sqrf(UTIL_MetresToGoldSrcUnits(5.0f)))
{
return WEAPON_MARINE_GL;
}
if (BotGetSecondaryWeaponClipAmmo(pBot) > 0)
{
return GetBotMarineSecondaryWeapon(pBot);
}
return WEAPON_MARINE_KNIFE;
}
if (DistFromEnemy <= sqrf(UTIL_MetresToGoldSrcUnits(2.0f)))
{
if (UTIL_GetPlayerPrimaryWeaponClipAmmo(pBot->Player) == 0)
{
if (BotGetSecondaryWeaponClipAmmo(pBot) > 0)
{
return GetBotMarineSecondaryWeapon(pBot);
}
else
{
return WEAPON_MARINE_KNIFE;
}
}
else
{
return UTIL_GetPlayerPrimaryWeapon(pBot->Player);
}
}
else
{
AvHAIWeapon PrimaryWeapon = UTIL_GetPlayerPrimaryWeapon(pBot->Player);
if (PrimaryWeapon == WEAPON_MARINE_SHOTGUN)
{
if (DistFromEnemy > sqrf(UTIL_MetresToGoldSrcUnits(10.0f)))
{
if (BotGetSecondaryWeaponClipAmmo(pBot) > 0 || BotGetSecondaryWeaponAmmoReserve(pBot) > 0)
{
return GetBotMarineSecondaryWeapon(pBot);
}
else
{
if (UTIL_GetPlayerPrimaryWeaponClipAmmo(pBot->Player) > 0 || UTIL_GetPlayerPrimaryAmmoReserve(pBot->Player) > 0)
{
return PrimaryWeapon;
}
else
{
return WEAPON_MARINE_KNIFE;
}
}
}
else
{
if (UTIL_GetPlayerPrimaryWeaponClipAmmo(pBot->Player) > 0 || UTIL_GetPlayerPrimaryAmmoReserve(pBot->Player) > 0)
{
return PrimaryWeapon;
}
else
{
if (BotGetSecondaryWeaponClipAmmo(pBot) > 0)
{
return GetBotMarineSecondaryWeapon(pBot);
}
else
{
return WEAPON_MARINE_KNIFE;
}
}
}
}
else
{
if (DistFromEnemy > sqrf(UTIL_MetresToGoldSrcUnits(5.0f)))
{
if (UTIL_GetPlayerPrimaryWeaponClipAmmo(pBot->Player) > 0 || UTIL_GetPlayerPrimaryAmmoReserve(pBot->Player) > 0)
{
return PrimaryWeapon;
}
if (BotGetSecondaryWeaponClipAmmo(pBot) > 0 || BotGetSecondaryWeaponAmmoReserve(pBot) > 0)
{
return GetBotMarineSecondaryWeapon(pBot);
}
return WEAPON_MARINE_KNIFE;
}
else
{
if (UTIL_GetPlayerPrimaryWeaponClipAmmo(pBot->Player) > 0 || (DistFromEnemy > sqrf(UTIL_MetresToGoldSrcUnits(5.0f)) && UTIL_GetPlayerPrimaryAmmoReserve(pBot->Player) > 0))
{
return PrimaryWeapon;
}
else
{
if (BotGetSecondaryWeaponClipAmmo(pBot) > 0)
{
return GetBotMarineSecondaryWeapon(pBot);
}
else
{
return WEAPON_MARINE_KNIFE;
}
}
}
}
}
} }
else else
{ {
@ -691,6 +575,14 @@ AvHAIWeapon BotMarineChooseBestWeapon(AvHAIPlayer* pBot, edict_t* target)
} }
} }
bool BotAnyWeaponNeedsReloading(AvHAIPlayer* pBot)
{
if (UTIL_GetPlayerPrimaryWeaponClipAmmo(pBot->Player) < UTIL_GetPlayerPrimaryWeaponMaxClipSize(pBot->Player) && UTIL_GetPlayerPrimaryAmmoReserve(pBot->Player) > 0) { return true; }
if (UTIL_GetPlayerSecondaryWeaponClipAmmo(pBot->Player) < UTIL_GetPlayerSecondaryWeaponMaxClipSize(pBot->Player) && UTIL_GetPlayerSecondaryAmmoReserve(pBot->Player) > 0) { return true; }
return false;
}
AvHAIWeapon BotAlienChooseBestWeaponForStructure(AvHAIPlayer* pBot, edict_t* target) AvHAIWeapon BotAlienChooseBestWeaponForStructure(AvHAIPlayer* pBot, edict_t* target)
{ {
AvHAIDeployableStructureType StructureType = GetStructureTypeFromEdict(target); AvHAIDeployableStructureType StructureType = GetStructureTypeFromEdict(target);
@ -772,6 +664,114 @@ AvHAIWeapon BotMarineChooseBestWeaponForStructure(AvHAIPlayer* pBot, edict_t* ta
return WEAPON_MARINE_KNIFE; return WEAPON_MARINE_KNIFE;
} }
AvHAIWeapon MarineGetBestWeaponForPlayerTarget(AvHAIPlayer* pBot, AvHPlayer* Target)
{
AvHAIWeapon PrimaryWeapon = UTIL_GetPlayerPrimaryWeapon(pBot->Player);
AvHAIWeapon SecondaryWeapon = UTIL_GetPlayerSecondaryWeapon(pBot->Player);
AvHAIWeapon CurrentWeapon = GetPlayerCurrentWeapon(pBot->Player);
float DistToEnemy = vDist2DSq(pBot->Edict->v.origin, Target->pev->origin);
bool bHasAmmoForPrimary = (PrimaryWeapon != WEAPON_INVALID && UTIL_GetPlayerPrimaryWeaponClipAmmo(pBot->Player) > 0 || UTIL_GetPlayerPrimaryAmmoReserve(pBot->Player) > 0);
bool bHasAmmoForSecondary = (SecondaryWeapon != WEAPON_INVALID && UTIL_GetPlayerSecondaryWeaponClipAmmo(pBot->Player) > 0 || UTIL_GetPlayerSecondaryAmmoReserve(pBot->Player) > 0);
if (PrimaryWeapon != WEAPON_INVALID && UTIL_GetPlayerPrimaryWeaponClipAmmo(pBot->Player) > 0)
{
if (PrimaryWeapon == WEAPON_MARINE_GL)
{
if (DistToEnemy > sqrf(BALANCE_VAR(kGrenadeRadius)) || !bHasAmmoForSecondary)
{
return PrimaryWeapon;
}
else
{
if (bHasAmmoForSecondary)
{
return SecondaryWeapon;
}
else
{
return WEAPON_MARINE_KNIFE;
}
}
}
else if (PrimaryWeapon == WEAPON_MARINE_SHOTGUN)
{
float MaxDist = (IsPlayerMarine(Target) || Target->GetUser3() > AVH_USER3_ALIEN_PLAYER3) ? UTIL_MetresToGoldSrcUnits(15.0f) : UTIL_MetresToGoldSrcUnits(8.0f);
// Give a little extra leeway if the bot is currently holding a shotgun. Helps prevent rapid switching if the enemy is right on the edge of the max distance
if (CurrentWeapon == PrimaryWeapon)
{
MaxDist *= 1.25f;
}
if (DistToEnemy < sqrf(MaxDist) || !bHasAmmoForSecondary)
{
return PrimaryWeapon;
}
else
{
if (bHasAmmoForSecondary)
{
return SecondaryWeapon;
}
else
{
return WEAPON_MARINE_KNIFE;
}
}
}
else
{
return PrimaryWeapon;
}
}
bool bEnemyIsRanged = IsPlayerMarine(Target) || ((GetPlayerCurrentWeapon(Target) == WEAPON_FADE_ACIDROCKET || GetPlayerCurrentWeapon(Target) == WEAPON_LERK_SPORES) && DistToEnemy > sqrf(UTIL_MetresToGoldSrcUnits(5.0f)));
if (bEnemyIsRanged)
{
if (bHasAmmoForSecondary)
{
return SecondaryWeapon;
}
else
{
return WEAPON_MARINE_KNIFE;
}
}
if (DistToEnemy > sqrf(UTIL_MetresToGoldSrcUnits(5.0f)))
{
if (bHasAmmoForPrimary)
{
return PrimaryWeapon;
}
else if (bHasAmmoForSecondary)
{
return SecondaryWeapon;
}
else
{
return WEAPON_MARINE_KNIFE;
}
}
if (UTIL_GetPlayerPrimaryWeaponClipAmmo(pBot->Player) > 0)
{
return PrimaryWeapon;
}
else if (UTIL_GetPlayerSecondaryWeaponClipAmmo(pBot->Player) > 0)
{
return SecondaryWeapon;
}
else
{
return WEAPON_MARINE_KNIFE;
}
}
AvHAIWeapon GorgeGetBestWeaponForCombatTarget(AvHAIPlayer* pBot, edict_t* Target) AvHAIWeapon GorgeGetBestWeaponForCombatTarget(AvHAIPlayer* pBot, edict_t* Target)
{ {
// Apparently I only imagined bile bomb doing damage to marine armour. Leaving it commented out in case we want to enable it again in future // Apparently I only imagined bile bomb doing damage to marine armour. Leaving it commented out in case we want to enable it again in future

View File

@ -43,8 +43,11 @@ bool IsMeleeWeapon(const AvHAIWeapon Weapon);
Vector UTIL_GetGrenadeThrowTarget(edict_t* Player, const Vector TargetLocation, const float ExplosionRadius, bool bPrecise); Vector UTIL_GetGrenadeThrowTarget(edict_t* Player, const Vector TargetLocation, const float ExplosionRadius, bool bPrecise);
AvHAIWeapon BotMarineChooseBestWeaponForStructure(AvHAIPlayer* pBot, edict_t* target); AvHAIWeapon BotMarineChooseBestWeaponForStructure(AvHAIPlayer* pBot, edict_t* target);
AvHAIWeapon MarineGetBestWeaponForPlayerTarget(AvHAIPlayer* pBot, AvHPlayer* Target);
AvHAIWeapon BotAlienChooseBestWeaponForStructure(AvHAIPlayer* pBot, edict_t* target); AvHAIWeapon BotAlienChooseBestWeaponForStructure(AvHAIPlayer* pBot, edict_t* target);
bool BotAnyWeaponNeedsReloading(AvHAIPlayer* pBot);
// Helper function to pick the best weapon for any given situation and target type. // Helper function to pick the best weapon for any given situation and target type.
AvHAIWeapon BotMarineChooseBestWeapon(AvHAIPlayer* pBot, edict_t* target); AvHAIWeapon BotMarineChooseBestWeapon(AvHAIPlayer* pBot, edict_t* target);
AvHAIWeapon BotAlienChooseBestWeapon(AvHAIPlayer* pBot, edict_t* target); AvHAIWeapon BotAlienChooseBestWeapon(AvHAIPlayer* pBot, edict_t* target);

View File

@ -86,7 +86,7 @@ extern int g_runfuncs;
#ifdef AVH_SERVER #ifdef AVH_SERVER
#include "AvHServerUtil.h" #include "AvHServerUtil.h"
#include "AvHGamerules.h" #include "AvHGamerules.h"
#include "AvHAISoundQueue.h"
extern int gWelderConstEventID; extern int gWelderConstEventID;
#endif #endif
@ -1048,11 +1048,32 @@ void AvHBasePlayerWeapon::PrimaryAttack(void)
this->PlaybackEvent(this->mEvent, this->GetShootAnimation()); this->PlaybackEvent(this->mEvent, this->GetShootAnimation());
this->SetAnimationAndSound(); this->SetAnimationAndSound();
// If player is too close to a wall, don't actually fire the projectile // If player is too close to a wall, don't actually fire the projectile
if(this->GetIsGunPositionValid()) if(this->GetIsGunPositionValid())
{ {
this->FireProjectiles(); this->FireProjectiles();
#ifdef AVH_SERVER
float SoundVolume = 1.0f;
int theSilenceLevel = AvHGetAlienUpgradeLevel(this->m_pPlayer->pev->iuser4, MASK_UPGRADE_6);
switch (theSilenceLevel)
{
case 1:
SoundVolume = (float)BALANCE_VAR(kSilenceLevel1Volume);
break;
case 2:
SoundVolume = (float)BALANCE_VAR(kSilenceLevel2Volume);
break;
case 3:
SoundVolume = (float)BALANCE_VAR(kSilenceLevel3Volume);
break;
}
AISND_RegisterNewSound(this->m_pPlayer->entindex(), this->m_pPlayer->pev->origin, AI_SOUND_SHOOT, SoundVolume);
#endif
} }
else else
{ {

View File

@ -64,6 +64,7 @@
#ifdef AVH_SERVER #ifdef AVH_SERVER
#include "AvHGamerules.h" #include "AvHGamerules.h"
#include "AvHServerUtil.h" #include "AvHServerUtil.h"
#include "AvHAISoundQueue.h"
#endif #endif
#include "AvHSharedUtil.h" #include "AvHSharedUtil.h"
@ -221,6 +222,8 @@ void AvHBite::FireProjectiles(void)
{ {
theSoundToPlay = kBiteKillSound; theSoundToPlay = kBiteKillSound;
} }
AISND_RegisterNewSound(this->m_pPlayer->entindex(), this->m_pPlayer->pev->origin, AI_SOUND_LANDING, 1.0f);
EMIT_SOUND(ENT(pev), CHAN_WEAPON, theSoundToPlay, 1.0, ATTN_NORM); EMIT_SOUND(ENT(pev), CHAN_WEAPON, theSoundToPlay, 1.0, ATTN_NORM);
} }

View File

@ -70,6 +70,7 @@
#ifdef AVH_SERVER #ifdef AVH_SERVER
#include "AvHGamerules.h" #include "AvHGamerules.h"
#include "AvHServerUtil.h" #include "AvHServerUtil.h"
#include "AvHAISoundQueue.h"
#endif #endif
#include "AvHSharedUtil.h" #include "AvHSharedUtil.h"
@ -235,6 +236,8 @@ void AvHClaws::FireProjectiles(void)
float theForceScalar = theDamage*.2f; float theForceScalar = theDamage*.2f;
CBaseEntity* theAttacker = this->m_pPlayer; CBaseEntity* theAttacker = this->m_pPlayer;
AvHSUExplosiveForce(pHurt->pev->origin, 100, theForceScalar, theAttacker, theAttacker); AvHSUExplosiveForce(pHurt->pev->origin, 100, theForceScalar, theAttacker, theAttacker);
AISND_RegisterNewSound(pHurt->entindex(), this->m_pPlayer->pev->origin, AI_SOUND_LANDING, 1.0f);
// Played in event now // Played in event now
//EMIT_SOUND_DYN(ENT(pev), CHAN_WEAPON, theSoundToPlay, 1.0, ATTN_NORM, 0, 100 + theAdrenalineFactor*30 + RANDOM_LONG(-3,3) ); //EMIT_SOUND_DYN(ENT(pev), CHAN_WEAPON, theSoundToPlay, 1.0, ATTN_NORM, 0, 100 + theAdrenalineFactor*30 + RANDOM_LONG(-3,3) );

View File

@ -146,7 +146,10 @@
#include "AvHSiegeTurret.h" #include "AvHSiegeTurret.h"
#include "AvHHulls.h" #include "AvHHulls.h"
#ifdef AVH_SERVER
#include "AvHAIPlayerManager.h" #include "AvHAIPlayerManager.h"
#include "AvHAISoundQueue.h"
#endif
//LINK_ENTITY_TO_CLASS(kwMine, AvHMine); //LINK_ENTITY_TO_CLASS(kwMine, AvHMine);
//LINK_ENTITY_TO_CLASS(kwDeployedTurret, AvHDeployedTurret); //LINK_ENTITY_TO_CLASS(kwDeployedTurret, AvHDeployedTurret);
@ -1286,6 +1289,10 @@ void AvHPhaseGate::TeleportUse(CBaseEntity *pActivator, CBaseEntity *pCaller, US
this->SetTimeOfLastDeparture(gpGlobals->time); this->SetTimeOfLastDeparture(gpGlobals->time);
AvHSUPlayPhaseInEffect(theFlags, this, thePlayer); AvHSUPlayPhaseInEffect(theFlags, this, thePlayer);
#ifdef AVH_SERVER
AISND_RegisterNewSound(thePlayer->entindex(), theOrigin, AI_SOUND_OTHER, 1.0f);
#endif
// AvHSUKillPlayersTouchingPlayer(thePlayer, this->pev); // AvHSUKillPlayersTouchingPlayer(thePlayer, this->pev);
AvHSUPushbackPlayersTouchingPlayer(thePlayer, this->pev); AvHSUPushbackPlayersTouchingPlayer(thePlayer, this->pev);
KillBuildablesTouchingPlayer(thePlayer, this->pev); KillBuildablesTouchingPlayer(thePlayer, this->pev);
@ -1978,11 +1985,13 @@ void AvHCommandStation::CommandUse( CBaseEntity* pActivator, CBaseEntity* pCalle
GetGameRules()->MarkDramaticEvent(kCCNewCommanderPriority, thePlayer, this); GetGameRules()->MarkDramaticEvent(kCCNewCommanderPriority, thePlayer, this);
#ifdef AVH_SERVER
// A human used the comm chair, let the AI know to keep away // A human used the comm chair, let the AI know to keep away
if (!(thePlayer->pev->flags & FL_FAKECLIENT)) if (!(thePlayer->pev->flags & FL_FAKECLIENT))
{ {
AIMGR_SetCommanderAllowedTime(theStationTeamNumber, gpGlobals->time + 20.0f); AIMGR_SetCommanderAllowedTime(theStationTeamNumber, gpGlobals->time + 20.0f);
} }
#endif
} }
else else
{ {

View File

@ -255,7 +255,10 @@
#include "AvHNetworkMessages.h" #include "AvHNetworkMessages.h"
#include "AvHNexusServer.h" #include "AvHNexusServer.h"
#ifdef AVH_SERVER
#include "AvHAIPlayerManager.h" #include "AvHAIPlayerManager.h"
#include "AvHAISoundQueue.h"
#endif
std::string GetLogStringForPlayer( edict_t *pEntity ); std::string GetLogStringForPlayer( edict_t *pEntity );
@ -2309,6 +2312,26 @@ void AvHPlayer::StartLeap()
// Make sure player has leap // Make sure player has leap
if(this->pev->iuser3 == AVH_USER3_ALIEN_PLAYER1) if(this->pev->iuser3 == AVH_USER3_ALIEN_PLAYER1)
{ {
#ifdef AVH_SERVER
float SoundVolume = 1.0f;
int theSilenceLevel = AvHGetAlienUpgradeLevel(this->pev->iuser4, MASK_UPGRADE_6);
switch (theSilenceLevel)
{
case 1:
SoundVolume = (float)BALANCE_VAR(kSilenceLevel1Volume);
break;
case 2:
SoundVolume = (float)BALANCE_VAR(kSilenceLevel2Volume);
break;
case 3:
SoundVolume = (float)BALANCE_VAR(kSilenceLevel3Volume);
break;
}
AISND_RegisterNewSound(this->entindex(), this->pev->origin, AI_SOUND_SHOOT, SoundVolume);
#endif
this->mTimeLeapEnd = gpGlobals->time + kLeapDuration; this->mTimeLeapEnd = gpGlobals->time + kLeapDuration;
} }
} }
@ -4973,6 +4996,11 @@ bool AvHPlayer::PlaySaying(AvHMessageID inMessageID)
//int pitch = 95;// + RANDOM_LONG(0,29); //int pitch = 95;// + RANDOM_LONG(0,29);
//EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, theSaying, 1, ATTN_NORM, 0, pitch); //EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, theSaying, 1, ATTN_NORM, 0, pitch);
gSoundListManager.PlaySoundInList(theSoundList, this, CHAN_VOICE, 1.0f); gSoundListManager.PlaySoundInList(theSoundList, this, CHAN_VOICE, 1.0f);
#ifdef AVH_SERVER
AISND_RegisterNewSound(this->entindex(), this->pev->origin, AI_SOUND_VOICELINE, 1.0f);
#endif
thePlayedSaying = true; thePlayedSaying = true;
} }
@ -7034,6 +7062,28 @@ void AvHPlayer::InternalMovementThink()
} }
} }
else { else {
#ifdef AVH_SERVER
float SoundVolume = 1.0f;
int theSilenceLevel = AvHGetAlienUpgradeLevel(this->pev->iuser4, MASK_UPGRADE_6);
switch (theSilenceLevel)
{
case 1:
SoundVolume = (float)BALANCE_VAR(kSilenceLevel1Volume);
break;
case 2:
SoundVolume = (float)BALANCE_VAR(kSilenceLevel2Volume);
break;
case 3:
SoundVolume = (float)BALANCE_VAR(kSilenceLevel3Volume);
break;
}
AISND_RegisterNewSound(this->entindex(), this->pev->origin, AI_SOUND_SHOOT, SoundVolume);
#endif
EMIT_SOUND_DYN(ENT(this->pev), CHAN_WEAPON, theSoundToPlay, theVolumeScalar, ATTN_NORM, 0, 100); EMIT_SOUND_DYN(ENT(this->pev), CHAN_WEAPON, theSoundToPlay, theVolumeScalar, ATTN_NORM, 0, 100);
this->mTimeOfLastMovementSound = gpGlobals->time; this->mTimeOfLastMovementSound = gpGlobals->time;
} }
@ -8753,6 +8803,10 @@ bool AvHPlayer::Heal(float inAmount, bool inPlaySound, bool dcHealing)
{ {
// Play regeneration event // Play regeneration event
PLAYBACK_EVENT_FULL(0, this->edict(), gRegenerationEventID, 0, this->pev->origin, (float *)&g_vecZero, this->GetAlienAdjustedEventVolume(), 0.0, /*theWeaponIndex*/ 0, 0, 0, 0 ); PLAYBACK_EVENT_FULL(0, this->edict(), gRegenerationEventID, 0, this->pev->origin, (float *)&g_vecZero, this->GetAlienAdjustedEventVolume(), 0.0, /*theWeaponIndex*/ 0, 0, 0, 0 );
#ifdef AVH_SERVER
// Heartbeat sound is a little loud, so reduce it for the AI so bots don't instantly spot your location with a single regen tic
AISND_RegisterNewSound(this->entindex(), this->pev->origin, AI_SOUND_OTHER, this->GetAlienAdjustedEventVolume() * 0.25f);
#endif
} }
} }
} }
@ -9177,7 +9231,8 @@ int AvHPlayer::TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, floa
{ {
CBasePlayer* inAttackingPlayer = dynamic_cast<CBasePlayer*>(CBaseEntity::Instance(ENT(pevAttacker))); CBasePlayer* inAttackingPlayer = dynamic_cast<CBasePlayer*>(CBaseEntity::Instance(ENT(pevAttacker)));
if (inAttackingPlayer) #ifdef AVH_SERVER
if (inAttackingPlayer && AIMGR_IsBotEnabled())
{ {
AvHAIPlayer* VictimBot = AIMGR_GetBotRefFromPlayer(this); AvHAIPlayer* VictimBot = AIMGR_GetBotRefFromPlayer(this);
@ -9186,7 +9241,7 @@ int AvHPlayer::TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, floa
AIPlayerTakeDamage(VictimBot, flDamage, inAttackingPlayer->edict()); AIPlayerTakeDamage(VictimBot, flDamage, inAttackingPlayer->edict());
} }
} }
#endif
const char* inWeaponName = STRING(pevInflictor->classname); const char* inWeaponName = STRING(pevInflictor->classname);
if(inAttackingPlayer && inWeaponName) if(inAttackingPlayer && inWeaponName)
{ {

View File

@ -123,6 +123,8 @@
#include "AvHHulls.h" #include "AvHHulls.h"
#include "AnimationUtil.h" #include "AnimationUtil.h"
#include "AvHAISoundQueue.h"
int NS_PointContents(const hull_t *hull, int num, float p[3]); int NS_PointContents(const hull_t *hull, int num, float p[3]);
float NS_TraceLineAgainstEntity(int inEntityIndex, float inTime, const float inRayOrigin[3], const float inRayDirection[3]); float NS_TraceLineAgainstEntity(int inEntityIndex, float inTime, const float inRayOrigin[3], const float inRayDirection[3]);
@ -573,6 +575,8 @@ void AvHSUPlayRandomConstructionEffect(AvHPlayer* inPlayer, CBaseEntity* inConst
{ {
gSoundListManager.PlaySoundInList(kMarineConstructionSoundList, inConstructee, CHAN_BODY, theVolume); gSoundListManager.PlaySoundInList(kMarineConstructionSoundList, inConstructee, CHAN_BODY, theVolume);
AISND_RegisterNewSound(inPlayer->entindex(), inPlayer->pev->origin, AI_SOUND_OTHER, theVolume);
// Play sparks every other time // Play sparks every other time
if(RANDOM_LONG(0, 1) == 1) if(RANDOM_LONG(0, 1) == 1)
{ {

View File

@ -67,6 +67,7 @@
#ifdef AVH_SERVER #ifdef AVH_SERVER
#include "AvHGamerules.h" #include "AvHGamerules.h"
#include "AvHServerUtil.h" #include "AvHServerUtil.h"
#include "AvHAISoundQueue.h"
#endif #endif
#include "AvHSharedUtil.h" #include "AvHSharedUtil.h"
@ -254,6 +255,8 @@ void AvHSwipe::FireProjectiles(void)
ASSERT(theSoundToPlay); ASSERT(theSoundToPlay);
EMIT_SOUND(ENT(pev), CHAN_WEAPON, theSoundToPlay, 1.0, ATTN_NORM); EMIT_SOUND(ENT(pev), CHAN_WEAPON, theSoundToPlay, 1.0, ATTN_NORM);
AISND_RegisterNewSound(pHurt->entindex(), this->m_pPlayer->pev->origin, AI_SOUND_LANDING, 1.0f);
} }
} }

View File

@ -107,6 +107,9 @@
#include "../mod/CollisionUtil.h" #include "../mod/CollisionUtil.h"
#include "../engine/studio.h" #include "../engine/studio.h"
#ifdef AVH_SERVER
#include "../mod/AvHAISoundQueue.h"
#endif
//#ifdef AVH_SERVER //#ifdef AVH_SERVER
#include "../engine/edict.h" #include "../engine/edict.h"
@ -2008,6 +2011,9 @@ void NS_PlayStepSound(int inMaterialType, int inSoundNumber, float inVolume)
// Play it at the specified volume // Play it at the specified volume
PM_NSPlaySound(CHAN_BODY, theFinalName, inVolume, theNorm, 0, PITCH_NORM); PM_NSPlaySound(CHAN_BODY, theFinalName, inVolume, theNorm, 0, PITCH_NORM);
#ifdef AVH_SERVER
AISND_RegisterNewSound(pmove->player_index + 1, pmove->origin, AI_SOUND_FOOTSTEP, inVolume);
#endif
} }
else else
{ {
@ -4613,6 +4619,10 @@ bool PM_FlapMove()
theVolumeScalar = min(max(theVolumeScalar, 0.0f), 1.0f); theVolumeScalar = min(max(theVolumeScalar, 0.0f), 1.0f);
PM_NSPlaySound(CHAN_BODY, theSoundToPlay, theVolumeScalar, ATTN_NORM, 0, PITCH_NORM); PM_NSPlaySound(CHAN_BODY, theSoundToPlay, theVolumeScalar, ATTN_NORM, 0, PITCH_NORM);
#ifdef AVH_SERVER
AISND_RegisterNewSound(pmove->player_index + 1, pmove->origin, AI_SOUND_FOOTSTEP, theVolumeScalar);
#endif
} }
pmove->oldbuttons |= IN_JUMP; // don't jump again until released pmove->oldbuttons |= IN_JUMP; // don't jump again until released
@ -5700,6 +5710,9 @@ void PM_CheckFalling( void )
//break; //break;
//case 1: //case 1:
PM_NSPlaySound( CHAN_VOICE, theFallPainSound, theFallPainVolume, ATTN_NORM, 0, PITCH_NORM ); PM_NSPlaySound( CHAN_VOICE, theFallPainSound, theFallPainVolume, ATTN_NORM, 0, PITCH_NORM );
#ifdef AVH_SERVER
AISND_RegisterNewSound(pmove->player_index + 1, pmove->origin, AI_SOUND_LANDING, theFallPainVolume);
#endif
// break; // break;
//} //}
fvol = 1.0; fvol = 1.0;