diff --git a/main/navmeshes/ns_eclipse.nav b/main/navmeshes/ns_eclipse.nav
index f25245fe..0142be3c 100644
Binary files a/main/navmeshes/ns_eclipse.nav and b/main/navmeshes/ns_eclipse.nav differ
diff --git a/main/nsbots.ini b/main/nsbots.ini
index 45d1ce43..c5ce194d 100644
--- a/main/nsbots.ini
+++ b/main/nsbots.ini
@@ -30,7 +30,7 @@ MarineReactionTime=0.4
MarineAimSkill=0.1
MarineMovementTracking=0.1
MarineViewSpeed=0.5
-AlienReactionTime=0.4
+AlienReactionTime=0.5
AlienAimSkill=0.2
AlienMovementTracking=0.2
AlienViewSpeed=0.75
@@ -89,4 +89,4 @@ TeamSize=co_kestrel:5/5
# ChamberSequence:movement/?/?
# Or if you want sensory always last, but movement and defence random, use
# ChamberSequence=?/?/sensory
-ChamberSequence=defense/movement/sensory
+ChamberSequence=?/?/?
diff --git a/main/source/dlls/hl.vcxproj b/main/source/dlls/hl.vcxproj
index e4d5c8ec..cd791f1a 100644
--- a/main/source/dlls/hl.vcxproj
+++ b/main/source/dlls/hl.vcxproj
@@ -256,6 +256,7 @@
+
@@ -1390,6 +1391,7 @@
+
diff --git a/main/source/dlls/hl.vcxproj.filters b/main/source/dlls/hl.vcxproj.filters
index 90e9f2a5..3a28518f 100644
--- a/main/source/dlls/hl.vcxproj.filters
+++ b/main/source/dlls/hl.vcxproj.filters
@@ -545,6 +545,9 @@
mod\bots
+
+ mod\bots
+
@@ -967,5 +970,8 @@
mod\bots
+
+ mod\bots
+
\ No newline at end of file
diff --git a/main/source/dlls/sound.cpp b/main/source/dlls/sound.cpp
index 1c172c72..10f8f867 100644
--- a/main/source/dlls/sound.cpp
+++ b/main/source/dlls/sound.cpp
@@ -25,6 +25,10 @@
#include "gamerules.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 );
@@ -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 );
}
else
+ {
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
diff --git a/main/source/mod/AvHAIConfig.cpp b/main/source/mod/AvHAIConfig.cpp
index cf39cbd4..36822cf0 100644
--- a/main/source/mod/AvHAIConfig.cpp
+++ b/main/source/mod/AvHAIConfig.cpp
@@ -718,7 +718,7 @@ void CONFIG_RegenerateIniFile()
fprintf(NewConfigFile, "# ChamberSequence:movement/?/?\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=defense/movement/sensory\n");
+ fprintf(NewConfigFile, "ChamberSequence=?/?/?\n");
fflush(NewConfigFile);
fclose(NewConfigFile);
diff --git a/main/source/mod/AvHAIConstants.h b/main/source/mod/AvHAIConstants.h
index 00946ad8..2cbb9e34 100644
--- a/main/source/mod/AvHAIConstants.h
+++ b/main/source/mod/AvHAIConstants.h
@@ -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 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 CertaintyOfLocation = 0.0f; // How sure the bot is where the enemy is if they're cloaked
} enemy_status;
@@ -804,6 +805,8 @@ typedef struct AVH_AI_PLAYER
float ServerUpdateDelta = 0.0f; // How long since 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;
diff --git a/main/source/mod/AvHAINavigation.cpp b/main/source/mod/AvHAINavigation.cpp
index ac8e2594..9882d724 100644
--- a/main/source/mod/AvHAINavigation.cpp
+++ b/main/source/mod/AvHAINavigation.cpp
@@ -2059,7 +2059,7 @@ dtStatus FindPathClosestToPoint(AvHAIPlayer* pBot, const BotMoveStyle MoveStyle,
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;
Vector LiftStart = 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)
{
- Vector vForward = UTIL_GetVectorNormal2D(EndPoint - StartPoint);
+ Vector vForward = UTIL_GetVectorNormal2D(EndPoint - pBot->Edict->v.origin);
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;
@@ -3713,6 +3718,10 @@ void BlockedMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector EndPoi
if (FaceDot < 0.95f)
{
float MoveSpeed = vSize2D(pBot->Edict->v.velocity);
+ if (MoveSpeed < 20.0f)
+ {
+ MoveSpeed = 100.0f;
+ }
Vector NewVelocity = vForward * MoveSpeed;
NewVelocity.z = pBot->Edict->v.velocity.z;
@@ -3729,6 +3738,11 @@ void JumpMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector EndPoint)
if (vIsZero(vForward))
{
vForward = UTIL_GetVectorNormal2D(EndPoint - StartPoint);
+
+ if (vIsZero(vForward))
+ {
+ vForward = UTIL_GetForwardVector2D(pBot->Edict->v.angles);
+ }
}
pBot->desiredMovementDir = vForward;
@@ -3746,6 +3760,10 @@ void JumpMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector EndPoint)
if (FaceDot < 0.95f)
{
float MoveSpeed = vSize2D(pBot->Edict->v.velocity);
+ if (MoveSpeed < 20.0f)
+ {
+ MoveSpeed = 100.0f;
+ }
Vector NewVelocity = vForward * MoveSpeed;
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; }
// 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));
@@ -4746,6 +4764,12 @@ void BlinkClimbMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector End
if (FaceDot < 0.95f)
{
float MoveSpeed = vSize2D(pBot->Edict->v.velocity);
+
+ if (MoveSpeed < 20.0f)
+ {
+ MoveSpeed = 100.0f;
+ }
+
Vector NewVelocity = MoveDir * MoveSpeed;
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;
ClearBotMovement(pBot);
+
return true;
}
@@ -6811,6 +6836,7 @@ void BotFollowSwimPath(AvHAIPlayer* pBot)
if (pBot->BotNavInfo.CurrentPath.size() == 0 || pBot->BotNavInfo.CurrentPathPoint >= pBot->BotNavInfo.CurrentPath.size())
{
ClearBotPath(pBot);
+ NAV_ClearMovementTask(pBot);
return;
}
@@ -6964,6 +6990,7 @@ void BotFollowPath(AvHAIPlayer* pBot)
MoveToWithoutNav(pBot, CurrentNode.Location);
pBot->BotNavInfo.StuckInfo.bPathFollowFailed = true;
ClearBotPath(pBot);
+ NAV_ClearMovementTask(pBot);
return;
}
@@ -7408,6 +7435,7 @@ void ClearBotStuck(AvHAIPlayer* pBot)
bool BotRecalcPath(AvHAIPlayer* pBot, const Vector Destination)
{
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);
@@ -8772,6 +8800,18 @@ void UTIL_PopulateDoors()
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);
}
@@ -8790,6 +8830,28 @@ nav_door* UTIL_GetNavDoorByEdict(const edict_t* DoorEdict)
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)
{
if (!LiftRef) { return nullptr; }
@@ -8801,15 +8863,20 @@ AvHAIOffMeshConnection* UTIL_GetOffMeshConnectionForLift(nav_door* LiftRef)
{
if (!(it->ConnectionFlags & SAMPLE_POLYFLAGS_LIFT)) { continue; }
- Vector LiftLocation = UTIL_GetCentreOfEntity(LiftRef->DoorEdict);
-
- float ThisDist = fminf(vDist3DSq(it->FromLocation, LiftLocation), vDist3DSq(it->ToLocation, LiftLocation));
-
- if (!NearestConnection || ThisDist < MinDist)
+ if (it->TargetObject == LiftRef->DoorEdict)
{
- NearestConnection = &(*it);
- MinDist = ThisDist;
+ return &(*it);
}
+
+ //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;
diff --git a/main/source/mod/AvHAINavigation.h b/main/source/mod/AvHAINavigation.h
index 0966f9c6..698c91b8 100644
--- a/main/source/mod/AvHAINavigation.h
+++ b/main/source/mod/AvHAINavigation.h
@@ -482,6 +482,7 @@ void UTIL_PopulateWeldableObstacles();
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_GetClosestLiftToPoints(const Vector StartPoint, const Vector EndPoint);
AvHAIOffMeshConnection* UTIL_GetOffMeshConnectionForLift(nav_door* LiftRef);
diff --git a/main/source/mod/AvHAIPlayer.cpp b/main/source/mod/AvHAIPlayer.cpp
index 7376e545..9f5ecdee 100644
--- a/main/source/mod/AvHAIPlayer.cpp
+++ b/main/source/mod/AvHAIPlayer.cpp
@@ -1353,6 +1353,9 @@ void BotUpdateView(AvHAIPlayer* pBot)
UpdateAIPlayerViewFrustum(pBot);
+ float ViewUpdateDelta = gpGlobals->time - pBot->LastViewUpdateTime;
+ ViewUpdateDelta = clampf(ViewUpdateDelta, 0.0f, 0.2f);
+
// Update list of currently visible players
for (int i = 1; i <= gpGlobals->maxClients; i++)
{
@@ -1378,6 +1381,10 @@ void BotUpdateView(AvHAIPlayer* pBot)
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)
{
continue;
@@ -1434,6 +1441,7 @@ void BotUpdateView(AvHAIPlayer* pBot)
if (bInFOV && (bCanSeeEnemy || bIsTracked))
{
+ TrackingInfo->CertaintyOfLocation = 1.0f;
Vector FloorLocation = UTIL_GetEntityGroundLocation(Enemy);
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);
@@ -1554,6 +1562,8 @@ void BotUpdateView(AvHAIPlayer* pBot)
{
pBot->LastSafeLocation = pBot->Edict->v.origin;
}
+
+
}
bool UTIL_IsCloakedPlayerInvisible(edict_t* Observer, AvHPlayer* Player)
@@ -1595,6 +1605,7 @@ void BotClearEnemyTrackingInfo(enemy_status* TrackingInfo)
TrackingInfo->LastSeenTime = 0.0f;
TrackingInfo->LastLOSPosition = ZERO_VECTOR;
TrackingInfo->LastHiddenPosition = ZERO_VECTOR;
+ TrackingInfo->CertaintyOfLocation = 0.0f;
}
void UpdateAIPlayerViewFrustum(AvHAIPlayer* pBot)
@@ -1895,23 +1906,25 @@ void EndBotFrame(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);
- if (pBot->CurrentEnemy < 0)
+ if (pBot->CurrentEnemy >= 0)
{
- MoveTo(pBot, AITAC_GetTeamStartingLocation(AIMGR_GetEnemyTeam(pBot->Player->GetTeam())), MOVESTYLE_NORMAL);
- }
- else
- {
- AlienCombatThink(pBot);
+ enemy_status* TrackingInfo = &pBot->TrackedEnemies[pBot->CurrentEnemy];
+
+ char msg[32];
+ sprintf(msg, "%.2f\n", TrackingInfo->CertaintyOfLocation);
+ 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)
{
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;
@@ -2575,7 +2618,7 @@ AvHAICombatStrategy GetFadeCombatStrategyForTarget(AvHAIPlayer* pBot, enemy_stat
{
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;
}
@@ -2583,7 +2626,7 @@ AvHAICombatStrategy GetFadeCombatStrategyForTarget(AvHAIPlayer* pBot, enemy_stat
}
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);
@@ -2683,7 +2726,7 @@ AvHAICombatStrategy GetMarineCombatStrategyForTarget(AvHAIPlayer* pBot, enemy_st
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 (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;
}
+ 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
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);
}
+
bool BombardierCombatThink(AvHAIPlayer* pBot)
{
return false;
@@ -2921,11 +2970,12 @@ bool RegularMarineCombatThink(AvHAIPlayer* pBot)
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)));
float LastEnemySeenTime = (TrackedEnemyRef->LastTrackedTime > 0.0f) ? TrackedEnemyRef->LastTrackedTime : TrackedEnemyRef->LastSeenTime;
+ float TimeSinceLastEnemySighting = gpGlobals->time - LastEnemySeenTime;
Vector LastEnemySeenLocation = TrackedEnemyRef->LastSeenLocation;
// Run away and restock
@@ -3017,15 +3067,29 @@ bool RegularMarineCombatThink(AvHAIPlayer* pBot)
// Maintain distance, pop and shoot
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))
{
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);
BotReloadWeapons(pBot);
return true;
@@ -3033,7 +3097,9 @@ bool RegularMarineCombatThink(AvHAIPlayer* pBot)
if (vDist2DSq(pBot->Edict->v.origin, pBot->LastSafeLocation) > sqrf(UTIL_MetresToGoldSrcUnits(3.0f)))
{
+ BotLookAt(pBot, TrackedEnemyRef->LastSeenLocation);
MoveTo(pBot, pBot->LastSafeLocation, MOVESTYLE_NORMAL);
+
}
else
{
@@ -3099,6 +3165,7 @@ bool RegularMarineCombatThink(AvHAIPlayer* pBot)
if (BotReloadWeapons(pBot)) { return true; }
+ BotLookAt(pBot, LastEnemySeenLocation);
MoveTo(pBot, LastEnemySeenLocation, MOVESTYLE_NORMAL);
}
@@ -3108,19 +3175,43 @@ bool RegularMarineCombatThink(AvHAIPlayer* pBot)
// Go for the kill. Maintain desired distance and pursue when needed
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);
-
- bool bCanReloadCurrentWeapon = (WeaponCanBeReloaded(DesiredCombatWeapon) && GetPlayerCurrentWeaponClipAmmo(pBot->Player) < GetPlayerCurrentWeaponMaxClipAmmo(pBot->Player) && GetPlayerCurrentWeaponReserveAmmo(pBot->Player) > 0);
- bool bMustReloadCurrentWeapon = bCanReloadCurrentWeapon && GetPlayerCurrentWeaponClipAmmo(pBot->Player) == 0;
+ if (GetPlayerCurrentWeapon(pBot->Player) != DesiredCombatWeapon)
+ {
+ return true;
+ }
if (vIsZero(pBot->LastSafeLocation))
{
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))
{
@@ -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);
- 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);
}
return true;
}
- MoveTo(pBot, TrackedEnemyRef->LastSeenLocation, MOVESTYLE_NORMAL);
+ BotGuardLocation(pBot, LastEnemySeenLocation);
return true;
}
+ if (bCanReloadCurrentWeapon && DistToEnemy > sqrf(DesiredDistance))
+ {
+ BotReloadWeapons(pBot);
+ }
+
BotAttackResult LOSCheck = PerformAttackLOSCheck(pBot, DesiredCombatWeapon, CurrentEnemy);
- if (bMustReloadCurrentWeapon)
+ if (LOSCheck != ATTACK_SUCCESS)
{
- MoveTo(pBot, pBot->LastSafeLocation, MOVESTYLE_NORMAL);
- BotReloadWeapons(pBot);
+ MoveTo(pBot, TrackedEnemyRef->LastSeenLocation, MOVESTYLE_NORMAL);
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);
- MoveTo(pBot, pBot->LastSafeLocation, MOVESTYLE_NORMAL);
- return true;
+ pBot->BotNavInfo.bZig = !pBot->BotNavInfo.bZig;
+ pBot->BotNavInfo.NextZigTime = gpGlobals->time + frandrange(0.5f, 1.0f);
}
- MoveTo(pBot, LastEnemySeenLocation, MOVESTYLE_NORMAL);
-
+ BotMovementInputs(pBot);
}
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);
-
- pBot->desiredMovementDir = (pBot->BotNavInfo.bZig) ? UTIL_GetVectorNormal2D(RightDir) : UTIL_GetVectorNormal2D(-RightDir);
-
- // Let's get ziggy with it
- if (gpGlobals->time > pBot->BotNavInfo.NextZigTime)
+ if (UTIL_PointIsDirectlyReachable(pBot->CurrentFloorPosition, RetreatLocation))
{
- pBot->BotNavInfo.bZig = !pBot->BotNavInfo.bZig;
- pBot->BotNavInfo.NextZigTime = gpGlobals->time + frandrange(0.5f, 1.0f);
+ 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);
+ }
}
- BotMovementInputs(pBot);
}
else
{
-
- 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
+ if (!UTIL_PlayerHasLOSToLocation(pBot->Edict, TrackedEnemyRef->LastSeenLocation, UTIL_MetresToGoldSrcUnits(5.0f)))
{
MoveTo(pBot, TrackedEnemyRef->LastSeenLocation, MOVESTYLE_NORMAL);
}
+ else
+ {
+ BotGuardLocation(pBot, TrackedEnemyRef->LastSeenLocation);
+ }
}
-
- BotShootTarget(pBot, DesiredCombatWeapon, CurrentEnemy);
}
+ BotShootTarget(pBot, DesiredCombatWeapon, CurrentEnemy);
+
return true;
}
diff --git a/main/source/mod/AvHAIPlayer.h b/main/source/mod/AvHAIPlayer.h
index 4c2e514f..521cf1a9 100644
--- a/main/source/mod/AvHAIPlayer.h
+++ b/main/source/mod/AvHAIPlayer.h
@@ -153,6 +153,7 @@ void UpdateAIPlayerDMRole(AvHAIPlayer* pBot);
bool ShouldAIPlayerTakeCommand(AvHAIPlayer* pBot);
void AIPlayerTakeDamage(AvHAIPlayer* pBot, int damageTaken, edict_t* aggressor);
+void AIPlayerHearEnemy(AvHAIPlayer* pBot, edict_t* HeardEnemy, float SoundVolume);
int BotGetNextEnemyTarget(AvHAIPlayer* pBot);
diff --git a/main/source/mod/AvHAIPlayerManager.cpp b/main/source/mod/AvHAIPlayerManager.cpp
index 042b7986..dbb6b750 100644
--- a/main/source/mod/AvHAIPlayerManager.cpp
+++ b/main/source/mod/AvHAIPlayerManager.cpp
@@ -8,6 +8,7 @@
#include "AvHAIHelper.h"
#include "AvHAICommander.h"
#include "AvHAIPlayerUtil.h"
+#include "AvHAISoundQueue.h"
#include "AvHGamerules.h"
#include "../dlls/client.h"
#include
@@ -51,6 +52,8 @@ float CountdownStartedTime = 0.0f;
bool bBotsEnabled = false;
+float CurrentFrameDelta = 0.01f;
+
AvHAICommanderMode AIMGR_GetCommanderMode()
{
if (avh_botcommandermode.value == 1)
@@ -560,6 +563,8 @@ void AIMGR_UpdateAIPlayers()
float FrameDelta = CurrTime - PrevTime;
+ AIMGR_SetFrameDelta(FrameDelta);
+
int cvarBotSkill = clampi((int)avh_botskill.value, 0, 3);
bool bSkillChanged = (cvarBotSkill != CurrentBotSkill);
@@ -592,6 +597,8 @@ void AIMGR_UpdateAIPlayers()
AIMGR_SetCommanderAllowedTime(TeamBNumber, gpGlobals->time + 15.0f);
}
}
+
+ AIMGR_ProcessPendingSounds();
}
int NumCommanders = AIMGR_GetNumAICommanders();
@@ -709,7 +716,7 @@ AvHTeamNumber AIMGR_GetTeamANumber()
AvHTeamNumber AIMGR_GetTeamBNumber()
{
- return GetGameRules()->GetTeamANumber();
+ return GetGameRules()->GetTeamBNumber();
}
AvHTeam* AIMGR_GetTeamRef(const AvHTeamNumber Team)
@@ -1450,4 +1457,100 @@ bool AIMGR_IsMatchPracticallyOver()
}
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;
}
\ No newline at end of file
diff --git a/main/source/mod/AvHAIPlayerManager.h b/main/source/mod/AvHAIPlayerManager.h
index 0be70044..9b50d6af 100644
--- a/main/source/mod/AvHAIPlayerManager.h
+++ b/main/source/mod/AvHAIPlayerManager.h
@@ -126,4 +126,9 @@ bool AIMGR_HasMatchEnded();
bool AIMGR_IsMatchPracticallyOver();
+void AIMGR_ProcessPendingSounds();
+
+void AIMGR_SetFrameDelta(float NewValue);
+float AIMGR_GetFrameDelta();
+
#endif
\ No newline at end of file
diff --git a/main/source/mod/AvHAISoundQueue.cpp b/main/source/mod/AvHAISoundQueue.cpp
new file mode 100644
index 00000000..3c0163a3
--- /dev/null
+++ b/main/source/mod/AvHAISoundQueue.cpp
@@ -0,0 +1,35 @@
+#include "AvHAISoundQueue.h"
+#include "AvHAIPlayerManager.h"
+
+std::vector 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();
+}
\ No newline at end of file
diff --git a/main/source/mod/AvHAISoundQueue.h b/main/source/mod/AvHAISoundQueue.h
new file mode 100644
index 00000000..d320c380
--- /dev/null
+++ b/main/source/mod/AvHAISoundQueue.h
@@ -0,0 +1,35 @@
+#ifndef AVH_AI_SOUND_QUEUE
+#define AVH_AI_SOUND_QUEUE
+
+
+#include
+
+// 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
\ No newline at end of file
diff --git a/main/source/mod/AvHAITask.cpp b/main/source/mod/AvHAITask.cpp
index 0d17f17d..c0c4dd39 100644
--- a/main/source/mod/AvHAITask.cpp
+++ b/main/source/mod/AvHAITask.cpp
@@ -1931,7 +1931,7 @@ void BotProgressEvolveTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
{
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))
{
diff --git a/main/source/mod/AvHAIWeaponHelper.cpp b/main/source/mod/AvHAIWeaponHelper.cpp
index c4478927..3abc0342 100644
--- a/main/source/mod/AvHAIWeaponHelper.cpp
+++ b/main/source/mod/AvHAIWeaponHelper.cpp
@@ -562,128 +562,12 @@ AvHAIWeapon BotMarineChooseBestWeapon(AvHAIPlayer* pBot, edict_t* target)
{
return GetBotMarineSecondaryWeapon(pBot);
}
- else
- {
- return UTIL_GetPlayerPrimaryWeapon(pBot->Player);
- }
+ return UTIL_GetPlayerPrimaryWeapon(pBot->Player);
}
if (IsEdictPlayer(target))
{
- float DistFromEnemy = vDist2DSq(pBot->Edict->v.origin, target->v.origin);
-
- 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;
- }
- }
- }
- }
- }
+ return MarineGetBestWeaponForPlayerTarget(pBot, dynamic_cast(CBaseEntity::Instance(target)));
}
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)
{
AvHAIDeployableStructureType StructureType = GetStructureTypeFromEdict(target);
@@ -772,6 +664,114 @@ AvHAIWeapon BotMarineChooseBestWeaponForStructure(AvHAIPlayer* pBot, edict_t* ta
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)
{
// 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
diff --git a/main/source/mod/AvHAIWeaponHelper.h b/main/source/mod/AvHAIWeaponHelper.h
index 589157d3..21034664 100644
--- a/main/source/mod/AvHAIWeaponHelper.h
+++ b/main/source/mod/AvHAIWeaponHelper.h
@@ -43,8 +43,11 @@ bool IsMeleeWeapon(const AvHAIWeapon Weapon);
Vector UTIL_GetGrenadeThrowTarget(edict_t* Player, const Vector TargetLocation, const float ExplosionRadius, bool bPrecise);
AvHAIWeapon BotMarineChooseBestWeaponForStructure(AvHAIPlayer* pBot, edict_t* target);
+AvHAIWeapon MarineGetBestWeaponForPlayerTarget(AvHAIPlayer* pBot, AvHPlayer* 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.
AvHAIWeapon BotMarineChooseBestWeapon(AvHAIPlayer* pBot, edict_t* target);
AvHAIWeapon BotAlienChooseBestWeapon(AvHAIPlayer* pBot, edict_t* target);
diff --git a/main/source/mod/AvHBasePlayerWeapon.cpp b/main/source/mod/AvHBasePlayerWeapon.cpp
index 10e55bbd..1bf1f654 100644
--- a/main/source/mod/AvHBasePlayerWeapon.cpp
+++ b/main/source/mod/AvHBasePlayerWeapon.cpp
@@ -86,7 +86,7 @@ extern int g_runfuncs;
#ifdef AVH_SERVER
#include "AvHServerUtil.h"
#include "AvHGamerules.h"
-
+#include "AvHAISoundQueue.h"
extern int gWelderConstEventID;
#endif
@@ -1048,11 +1048,32 @@ void AvHBasePlayerWeapon::PrimaryAttack(void)
this->PlaybackEvent(this->mEvent, this->GetShootAnimation());
this->SetAnimationAndSound();
+
+
// If player is too close to a wall, don't actually fire the projectile
if(this->GetIsGunPositionValid())
{
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
{
diff --git a/main/source/mod/AvHBite.cpp b/main/source/mod/AvHBite.cpp
index 7c0cc51b..94ed7e40 100644
--- a/main/source/mod/AvHBite.cpp
+++ b/main/source/mod/AvHBite.cpp
@@ -64,6 +64,7 @@
#ifdef AVH_SERVER
#include "AvHGamerules.h"
#include "AvHServerUtil.h"
+#include "AvHAISoundQueue.h"
#endif
#include "AvHSharedUtil.h"
@@ -221,6 +222,8 @@ void AvHBite::FireProjectiles(void)
{
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);
}
diff --git a/main/source/mod/AvHClaws.cpp b/main/source/mod/AvHClaws.cpp
index fc401f0b..1faf4986 100644
--- a/main/source/mod/AvHClaws.cpp
+++ b/main/source/mod/AvHClaws.cpp
@@ -70,6 +70,7 @@
#ifdef AVH_SERVER
#include "AvHGamerules.h"
#include "AvHServerUtil.h"
+#include "AvHAISoundQueue.h"
#endif
#include "AvHSharedUtil.h"
@@ -235,6 +236,8 @@ void AvHClaws::FireProjectiles(void)
float theForceScalar = theDamage*.2f;
CBaseEntity* theAttacker = this->m_pPlayer;
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
//EMIT_SOUND_DYN(ENT(pev), CHAN_WEAPON, theSoundToPlay, 1.0, ATTN_NORM, 0, 100 + theAdrenalineFactor*30 + RANDOM_LONG(-3,3) );
diff --git a/main/source/mod/AvHMarineEquipment.cpp b/main/source/mod/AvHMarineEquipment.cpp
index bbb89a2e..763cc839 100644
--- a/main/source/mod/AvHMarineEquipment.cpp
+++ b/main/source/mod/AvHMarineEquipment.cpp
@@ -146,7 +146,10 @@
#include "AvHSiegeTurret.h"
#include "AvHHulls.h"
+#ifdef AVH_SERVER
#include "AvHAIPlayerManager.h"
+#include "AvHAISoundQueue.h"
+#endif
//LINK_ENTITY_TO_CLASS(kwMine, AvHMine);
//LINK_ENTITY_TO_CLASS(kwDeployedTurret, AvHDeployedTurret);
@@ -1286,6 +1289,10 @@ void AvHPhaseGate::TeleportUse(CBaseEntity *pActivator, CBaseEntity *pCaller, US
this->SetTimeOfLastDeparture(gpGlobals->time);
AvHSUPlayPhaseInEffect(theFlags, this, thePlayer);
+#ifdef AVH_SERVER
+ AISND_RegisterNewSound(thePlayer->entindex(), theOrigin, AI_SOUND_OTHER, 1.0f);
+#endif
+
// AvHSUKillPlayersTouchingPlayer(thePlayer, this->pev);
AvHSUPushbackPlayersTouchingPlayer(thePlayer, this->pev);
KillBuildablesTouchingPlayer(thePlayer, this->pev);
@@ -1978,11 +1985,13 @@ void AvHCommandStation::CommandUse( CBaseEntity* pActivator, CBaseEntity* pCalle
GetGameRules()->MarkDramaticEvent(kCCNewCommanderPriority, thePlayer, this);
+#ifdef AVH_SERVER
// A human used the comm chair, let the AI know to keep away
if (!(thePlayer->pev->flags & FL_FAKECLIENT))
{
AIMGR_SetCommanderAllowedTime(theStationTeamNumber, gpGlobals->time + 20.0f);
}
+#endif
}
else
{
diff --git a/main/source/mod/AvHPlayer.cpp b/main/source/mod/AvHPlayer.cpp
index d8d58346..785f8f4e 100644
--- a/main/source/mod/AvHPlayer.cpp
+++ b/main/source/mod/AvHPlayer.cpp
@@ -255,7 +255,10 @@
#include "AvHNetworkMessages.h"
#include "AvHNexusServer.h"
+#ifdef AVH_SERVER
#include "AvHAIPlayerManager.h"
+#include "AvHAISoundQueue.h"
+#endif
std::string GetLogStringForPlayer( edict_t *pEntity );
@@ -2309,6 +2312,26 @@ void AvHPlayer::StartLeap()
// Make sure player has leap
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;
}
}
@@ -4973,6 +4996,11 @@ bool AvHPlayer::PlaySaying(AvHMessageID inMessageID)
//int pitch = 95;// + RANDOM_LONG(0,29);
//EMIT_SOUND_DYN(ENT(pev), CHAN_VOICE, theSaying, 1, ATTN_NORM, 0, pitch);
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;
}
@@ -7034,6 +7062,28 @@ void AvHPlayer::InternalMovementThink()
}
}
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);
this->mTimeOfLastMovementSound = gpGlobals->time;
}
@@ -8753,6 +8803,10 @@ bool AvHPlayer::Heal(float inAmount, bool inPlaySound, bool dcHealing)
{
// 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 );
+#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(CBaseEntity::Instance(ENT(pevAttacker)));
- if (inAttackingPlayer)
+#ifdef AVH_SERVER
+ if (inAttackingPlayer && AIMGR_IsBotEnabled())
{
AvHAIPlayer* VictimBot = AIMGR_GetBotRefFromPlayer(this);
@@ -9186,7 +9241,7 @@ int AvHPlayer::TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, floa
AIPlayerTakeDamage(VictimBot, flDamage, inAttackingPlayer->edict());
}
}
-
+#endif
const char* inWeaponName = STRING(pevInflictor->classname);
if(inAttackingPlayer && inWeaponName)
{
diff --git a/main/source/mod/AvHServerUtil.cpp b/main/source/mod/AvHServerUtil.cpp
index 773f874e..7c76d72f 100644
--- a/main/source/mod/AvHServerUtil.cpp
+++ b/main/source/mod/AvHServerUtil.cpp
@@ -123,6 +123,8 @@
#include "AvHHulls.h"
#include "AnimationUtil.h"
+#include "AvHAISoundQueue.h"
+
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]);
@@ -573,6 +575,8 @@ void AvHSUPlayRandomConstructionEffect(AvHPlayer* inPlayer, CBaseEntity* inConst
{
gSoundListManager.PlaySoundInList(kMarineConstructionSoundList, inConstructee, CHAN_BODY, theVolume);
+ AISND_RegisterNewSound(inPlayer->entindex(), inPlayer->pev->origin, AI_SOUND_OTHER, theVolume);
+
// Play sparks every other time
if(RANDOM_LONG(0, 1) == 1)
{
diff --git a/main/source/mod/AvHSwipe.cpp b/main/source/mod/AvHSwipe.cpp
index 9b0f6d1c..0b6090c1 100644
--- a/main/source/mod/AvHSwipe.cpp
+++ b/main/source/mod/AvHSwipe.cpp
@@ -67,6 +67,7 @@
#ifdef AVH_SERVER
#include "AvHGamerules.h"
#include "AvHServerUtil.h"
+#include "AvHAISoundQueue.h"
#endif
#include "AvHSharedUtil.h"
@@ -254,6 +255,8 @@ void AvHSwipe::FireProjectiles(void)
ASSERT(theSoundToPlay);
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);
}
}
diff --git a/main/source/pm_shared/pm_shared.cpp b/main/source/pm_shared/pm_shared.cpp
index 980c8356..795a8bad 100644
--- a/main/source/pm_shared/pm_shared.cpp
+++ b/main/source/pm_shared/pm_shared.cpp
@@ -107,6 +107,9 @@
#include "../mod/CollisionUtil.h"
#include "../engine/studio.h"
+#ifdef AVH_SERVER
+#include "../mod/AvHAISoundQueue.h"
+#endif
//#ifdef AVH_SERVER
#include "../engine/edict.h"
@@ -2008,6 +2011,9 @@ void NS_PlayStepSound(int inMaterialType, int inSoundNumber, float inVolume)
// Play it at the specified volume
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
{
@@ -4613,6 +4619,10 @@ bool PM_FlapMove()
theVolumeScalar = min(max(theVolumeScalar, 0.0f), 1.0f);
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
@@ -5700,6 +5710,9 @@ void PM_CheckFalling( void )
//break;
//case 1:
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;
//}
fvol = 1.0;