mirror of
https://github.com/ENSL/NS.git
synced 2024-11-10 15:21:54 +00:00
Bots understand trigger_changetarget
Bots can now navigate doors operated with a trigger_changetarget so they understand the sequence in which triggers must be activated to make it work
This commit is contained in:
parent
b336ec028c
commit
e4d82bef2e
8 changed files with 224 additions and 178 deletions
|
@ -2011,27 +2011,6 @@ void CTriggerGravity::GravityTouch( CBaseEntity *pOther )
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// this is a really bad idea.
|
||||
class CTriggerChangeTarget : public CBaseDelay
|
||||
{
|
||||
public:
|
||||
void KeyValue( KeyValueData *pkvd );
|
||||
void Spawn( void );
|
||||
void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
|
||||
|
||||
int ObjectCaps( void ) { return CBaseDelay::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; }
|
||||
virtual int Save( CSave &save );
|
||||
virtual int Restore( CRestore &restore );
|
||||
|
||||
static TYPEDESCRIPTION m_SaveData[];
|
||||
|
||||
private:
|
||||
int m_iszNewTarget;
|
||||
};
|
||||
LINK_ENTITY_TO_CLASS( trigger_changetarget, CTriggerChangeTarget );
|
||||
|
||||
TYPEDESCRIPTION CTriggerChangeTarget::m_SaveData[] =
|
||||
|
|
|
@ -59,6 +59,26 @@ private:
|
|||
CMultiManager* Clone(void);
|
||||
};
|
||||
|
||||
// this is a really bad idea.
|
||||
class CTriggerChangeTarget : public CBaseDelay
|
||||
{
|
||||
public:
|
||||
void KeyValue(KeyValueData* pkvd);
|
||||
void Spawn(void);
|
||||
void Use(CBaseEntity* pActivator, CBaseEntity* pCaller, USE_TYPE useType, float value);
|
||||
|
||||
int GetNewTargetName() { return m_iszNewTarget; }
|
||||
|
||||
int ObjectCaps(void) { return CBaseDelay::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; }
|
||||
virtual int Save(CSave& save);
|
||||
virtual int Restore(CRestore& restore);
|
||||
|
||||
static TYPEDESCRIPTION m_SaveData[];
|
||||
|
||||
private:
|
||||
int m_iszNewTarget;
|
||||
};
|
||||
|
||||
|
||||
class CLadder : public CBaseTrigger
|
||||
{
|
||||
|
|
|
@ -2333,6 +2333,10 @@ void CheckAndHandleDoorObstruction(AvHAIPlayer* pBot)
|
|||
{
|
||||
AITASK_SetWeldTask(pBot, &pBot->BotNavInfo.MovementTask, Trigger->Edict, true);
|
||||
}
|
||||
else if (Trigger->TriggerType == DOOR_BREAK)
|
||||
{
|
||||
AITASK_SetAttackTask(pBot, &pBot->BotNavInfo.MovementTask, Trigger->Edict, true);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
@ -3227,7 +3231,6 @@ void LadderMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector EndPoin
|
|||
pBot->Button |= IN_DUCK;
|
||||
}
|
||||
|
||||
|
||||
if (pBot->Player->IsOnLadder())
|
||||
{
|
||||
// We're on the ladder and actively climbing
|
||||
|
@ -3430,6 +3433,11 @@ void LadderMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector EndPoin
|
|||
// If we're going down the ladder and are approaching it, just keep moving towards it
|
||||
if (pBot->BotNavInfo.IsOnGround && !bIsGoingUpLadder)
|
||||
{
|
||||
if (vDist2DSq(pEdict->v.origin, StartPoint) < sqrf(32.0f))
|
||||
{
|
||||
pBot->BotNavInfo.bShouldWalk = true;
|
||||
}
|
||||
|
||||
Vector ApproachDir = UTIL_GetVectorNormal2D(EndPoint - pBot->Edict->v.origin);
|
||||
|
||||
float Dot = UTIL_GetDotProduct2D(ApproachDir, vForward);
|
||||
|
@ -5351,6 +5359,14 @@ void SkipAheadInFlightPath(AvHAIPlayer* pBot)
|
|||
// Early exit if we don't have a path, or we're already on the last path point
|
||||
if (BotNavInfo->CurrentPath.size() == 0 || BotNavInfo->CurrentPathPoint == prev(BotNavInfo->CurrentPath.end())) { return; }
|
||||
|
||||
|
||||
|
||||
if (UTIL_QuickHullTrace(pBot->Edict, pBot->Edict->v.origin, prev(BotNavInfo->CurrentPath.end())->Location, head_hull))
|
||||
{
|
||||
pBot->BotNavInfo.CurrentPathPoint = prev(BotNavInfo->CurrentPath.end());
|
||||
return;
|
||||
}
|
||||
|
||||
// If we are currently in a low area or approaching one, don't try to skip ahead in case it screws us up
|
||||
if (BotNavInfo->CurrentPathPoint->area == SAMPLE_POLYAREA_CROUCH || (next(BotNavInfo->CurrentPathPoint) != BotNavInfo->CurrentPath.end() && next(BotNavInfo->CurrentPathPoint)->area == SAMPLE_POLYAREA_CROUCH)) { return; }
|
||||
|
||||
|
@ -5414,11 +5430,7 @@ void BotFollowFlightPath(AvHAIPlayer* pBot)
|
|||
|
||||
ClosestPointToPath = vClosestPointOnLine(MoveFrom, CurrentMoveDest, pEdict->v.origin);
|
||||
|
||||
Vector MoveDir = UTIL_GetVectorNormal(CurrentMoveDest - pEdict->v.origin);
|
||||
|
||||
Vector ObstacleCheck = pEdict->v.origin + (MoveDir * 32.0f);
|
||||
|
||||
pEdict->v.origin = ClosestPointToPath;
|
||||
Vector MoveDir = UTIL_GetVectorNormal(CurrentMoveDest - MoveFrom);
|
||||
|
||||
if (IsBotStuck(pBot, CurrentMoveDest))
|
||||
{
|
||||
|
@ -5429,13 +5441,28 @@ void BotFollowFlightPath(AvHAIPlayer* pBot)
|
|||
}
|
||||
}
|
||||
|
||||
float Velocity = vSize2DSq(pEdict->v.velocity);
|
||||
float CurrentSpeed = vSize3D(pEdict->v.velocity);
|
||||
|
||||
if (vDist2DSq(pEdict->v.origin, MoveFrom) > sqrf(100.0f) && vDist2DSq(pEdict->v.origin, CurrentMoveDest) > sqrf(100.0f))
|
||||
{
|
||||
|
||||
Vector NewVelocity = MoveDir;
|
||||
|
||||
if (vDist3DSq(pEdict->v.origin, ClosestPointToPath) > sqrf(16.0f))
|
||||
{
|
||||
NewVelocity = UTIL_GetVectorNormal((ClosestPointToPath + (MoveDir * 100.0f)) - pEdict->v.origin);
|
||||
}
|
||||
|
||||
NewVelocity = NewVelocity * CurrentSpeed;
|
||||
pEdict->v.velocity = NewVelocity;
|
||||
|
||||
}
|
||||
|
||||
bool bMustHugGround = (CurrentMoveArea == SAMPLE_POLYAREA_CROUCH || NextMoveArea == SAMPLE_POLYAREA_CROUCH);
|
||||
|
||||
if (!bMustHugGround || MoveFrom.z <= CurrentMoveDest.z)
|
||||
{
|
||||
if (Velocity < sqrf(500.f))
|
||||
if (CurrentSpeed < sqrf(500.f))
|
||||
{
|
||||
if (!(pEdict->v.oldbuttons & IN_JUMP))
|
||||
{
|
||||
|
@ -5520,7 +5547,8 @@ void BotFollowSwimPath(AvHAIPlayer* pBot)
|
|||
|
||||
float WaterDiff = WaterLevel - pEdict->v.origin.z;
|
||||
|
||||
if (WaterDiff > 0.0f)
|
||||
// If we're below the waterline by a significant amount, then swim up to surface before we move on
|
||||
if (WaterDiff > 5.0f)
|
||||
{
|
||||
Vector MoveDir = UTIL_GetVectorNormal2D(BotNavInfo->CurrentPathPoint->Location - pEdict->v.origin);
|
||||
pBot->desiredMovementDir = MoveDir;
|
||||
|
@ -5537,7 +5565,15 @@ void BotFollowSwimPath(AvHAIPlayer* pBot)
|
|||
return;
|
||||
}
|
||||
|
||||
NewMove(pBot);
|
||||
// We're at the surface, now tackle the path the usual way
|
||||
if (pBot->BotNavInfo.NavProfile.bFlyingProfile)
|
||||
{
|
||||
BotFollowFlightPath(pBot);
|
||||
}
|
||||
else
|
||||
{
|
||||
BotFollowPath(pBot);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -6615,8 +6651,9 @@ void UTIL_PopulateTriggersForEntity(edict_t* Entity, vector<DoorTrigger>& Trigge
|
|||
CBaseButton* ButtonRef = dynamic_cast<CBaseButton*>(EntityRef);
|
||||
AvHWeldable* WeldableRef = dynamic_cast<AvHWeldable*>(EntityRef);
|
||||
CBaseTrigger* TriggerRef = dynamic_cast<CBaseTrigger*>(EntityRef);
|
||||
CBreakable* BreakableRef = dynamic_cast<CBreakable*>(EntityRef);
|
||||
|
||||
if (ButtonRef || WeldableRef || TriggerRef)
|
||||
if (ButtonRef || WeldableRef || TriggerRef || BreakableRef)
|
||||
{
|
||||
CBaseToggle* ToggleRef = dynamic_cast<CBaseToggle*>(EntityRef);
|
||||
|
||||
|
@ -6634,6 +6671,10 @@ void UTIL_PopulateTriggersForEntity(edict_t* Entity, vector<DoorTrigger>& Trigge
|
|||
{
|
||||
NewTriggerType = DOOR_WELD;
|
||||
}
|
||||
else if (BreakableRef)
|
||||
{
|
||||
NewTriggerType = DOOR_BREAK;
|
||||
}
|
||||
|
||||
DoorTrigger NewTrigger;
|
||||
NewTrigger.Entity = EntityRef;
|
||||
|
@ -6680,11 +6721,11 @@ void UTIL_PopulateTriggersForEntity(edict_t* Entity, vector<DoorTrigger>& Trigge
|
|||
if (FStrEq(STRING(EnvGlobalRef->m_globalstate), GlobalName))
|
||||
{
|
||||
UTIL_PopulateTriggersForEntity(EnvGlobalRef->edict(), TriggerList);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
return;
|
||||
}
|
||||
|
||||
const char* EntityName = STRING(Entity->v.targetname);
|
||||
|
@ -6703,6 +6744,47 @@ void UTIL_PopulateTriggersForEntity(edict_t* Entity, vector<DoorTrigger>& Trigge
|
|||
}
|
||||
END_FOR_ALL_ENTITIES(kwsWeldableClassName)
|
||||
|
||||
FOR_ALL_ENTITIES("trigger_changetarget", CTriggerChangeTarget*)
|
||||
|
||||
const char* TargetName = STRING(theEntity->pev->targetname);
|
||||
const char* NewTargetName = STRING(theEntity->GetNewTargetName());
|
||||
|
||||
if (FStrEq(STRING(theEntity->GetNewTargetName()), EntityName))
|
||||
{
|
||||
currTrigger = NULL;
|
||||
|
||||
while ((currTrigger = UTIL_FindEntityByString(currTrigger, "target", STRING(theEntity->pev->targetname))) != NULL)
|
||||
{
|
||||
UTIL_PopulateTriggersForEntity(currTrigger->edict(), TriggerList);
|
||||
}
|
||||
|
||||
currTrigger = NULL;
|
||||
|
||||
while ((currTrigger = UTIL_FindEntityByString(currTrigger, "targetname", STRING(theEntity->pev->target))) != NULL)
|
||||
{
|
||||
UTIL_PopulateTriggersForEntity(currTrigger->edict(), TriggerList);
|
||||
}
|
||||
|
||||
string NewString = TargetName;
|
||||
|
||||
CBaseEntity* CurrWeldable = NULL;
|
||||
|
||||
while ((CurrWeldable = UTIL_FindEntityByClassname(CurrWeldable, kwsWeldableClassName)) != NULL)
|
||||
{
|
||||
AvHWeldable* ThisWeldableRef = dynamic_cast<AvHWeldable*>(CurrWeldable);
|
||||
|
||||
if (ThisWeldableRef)
|
||||
{
|
||||
if (ThisWeldableRef->GetTargetOnFinish() == NewString)
|
||||
{
|
||||
UTIL_PopulateTriggersForEntity(ThisWeldableRef->edict(), TriggerList);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
END_FOR_ALL_ENTITIES("trigger_changetarget")
|
||||
|
||||
|
||||
while (((currTrigger = UTIL_FindEntityByClassname(currTrigger, "multi_manager")) != NULL))
|
||||
{
|
||||
|
@ -6746,130 +6828,6 @@ void UTIL_PopulateTriggersForEntity(edict_t* Entity, vector<DoorTrigger>& Trigge
|
|||
|
||||
}
|
||||
|
||||
void UTIL_LinkTriggerToDoor(const edict_t* DoorEdict, nav_door* DoorRef)
|
||||
{
|
||||
|
||||
CBaseEntity* currTrigger = NULL;
|
||||
const char* DoorTargetName = STRING(DoorEdict->v.targetname);
|
||||
while ((currTrigger = UTIL_FindEntityByString(currTrigger, "target", DoorTargetName)) != NULL)
|
||||
{
|
||||
CBaseToggle* ToggleRef = dynamic_cast<CBaseToggle*>(currTrigger);
|
||||
CBaseTrigger* TriggerRef = dynamic_cast<CBaseTrigger*>(currTrigger);
|
||||
CBaseButton* ButtonRef = dynamic_cast<CBaseButton*>(currTrigger);
|
||||
|
||||
DoorActivationType NewTriggerType = DOOR_NONE;
|
||||
|
||||
if (TriggerRef)
|
||||
{
|
||||
NewTriggerType = DOOR_TRIGGER;
|
||||
}
|
||||
else if (ButtonRef)
|
||||
{
|
||||
NewTriggerType = DOOR_BUTTON;
|
||||
}
|
||||
|
||||
DoorTrigger NewTrigger;
|
||||
NewTrigger.Entity = currTrigger;
|
||||
NewTrigger.Edict = currTrigger->edict();
|
||||
NewTrigger.ToggleEnt = ToggleRef;
|
||||
NewTrigger.TriggerType = NewTriggerType;
|
||||
NewTrigger.bIsActivated = !currTrigger->IsLockedByMaster();
|
||||
|
||||
DoorRef->TriggerEnts.push_back(NewTrigger);
|
||||
}
|
||||
|
||||
const string DoorName = DoorTargetName;
|
||||
|
||||
currTrigger = NULL;
|
||||
|
||||
FOR_ALL_ENTITIES(kwsWeldableClassName, AvHWeldable*)
|
||||
if (theEntity->GetTargetOnFinish() == DoorName)
|
||||
{
|
||||
DoorTrigger NewTrigger;
|
||||
NewTrigger.Entity = theEntity;
|
||||
NewTrigger.Edict = theEntity->edict();
|
||||
NewTrigger.TriggerType = DOOR_WELD;
|
||||
NewTrigger.bIsActivated = !theEntity->IsLockedByMaster();
|
||||
|
||||
DoorRef->TriggerEnts.push_back(NewTrigger);
|
||||
}
|
||||
END_FOR_ALL_ENTITIES(kwsWeldableClassName)
|
||||
|
||||
|
||||
|
||||
// If a door is activated via a multi_manager entity, then we need to find whatever trigger/button targets that multi_manager and tie it to the door
|
||||
|
||||
while (((currTrigger = UTIL_FindEntityByClassname(currTrigger, "multi_manager")) != NULL))
|
||||
{
|
||||
CMultiManager* MMRef = dynamic_cast<CMultiManager*>(currTrigger);
|
||||
|
||||
bool bTargetsDoor = false;
|
||||
|
||||
if (MMRef)
|
||||
{
|
||||
for (int i = 0; i < MMRef->m_cTargets; i++)
|
||||
{
|
||||
if (FStrEq(STRING(DoorEdict->v.targetname), STRING(MMRef->m_iTargetName[i])))
|
||||
{
|
||||
bTargetsDoor = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bTargetsDoor)
|
||||
{
|
||||
CBaseEntity* MMTrigger = NULL;
|
||||
|
||||
const char* MMNameChar = STRING(MMRef->pev->targetname);
|
||||
|
||||
while ((MMTrigger = UTIL_FindEntityByString(MMTrigger, "target", MMNameChar)) != NULL)
|
||||
{
|
||||
DoorActivationType NewTriggerType = DOOR_NONE;
|
||||
|
||||
CBaseToggle* ToggleRef = dynamic_cast<CBaseToggle*>(MMTrigger);
|
||||
CBaseTrigger* TriggerRef = dynamic_cast<CBaseTrigger*>(MMTrigger);
|
||||
CBaseButton* ButtonRef = dynamic_cast<CBaseButton*>(MMTrigger);
|
||||
|
||||
if (TriggerRef)
|
||||
{
|
||||
NewTriggerType = DOOR_TRIGGER;
|
||||
}
|
||||
else if (ButtonRef)
|
||||
{
|
||||
NewTriggerType = DOOR_BUTTON;
|
||||
}
|
||||
|
||||
DoorTrigger NewTrigger;
|
||||
NewTrigger.Entity = currTrigger;
|
||||
NewTrigger.Edict = currTrigger->edict();
|
||||
NewTrigger.ToggleEnt = ToggleRef;
|
||||
NewTrigger.TriggerType = NewTriggerType;
|
||||
NewTrigger.bIsActivated = currTrigger->IsLockedByMaster();
|
||||
|
||||
DoorRef->TriggerEnts.push_back(NewTrigger);
|
||||
}
|
||||
|
||||
const string MMName = MMNameChar;
|
||||
|
||||
FOR_ALL_ENTITIES(kwsWeldableClassName, AvHWeldable*)
|
||||
if (theEntity->GetTargetOnFinish() == MMName)
|
||||
{
|
||||
DoorTrigger NewTrigger;
|
||||
NewTrigger.Entity = theEntity;
|
||||
NewTrigger.Edict = theEntity->edict();
|
||||
NewTrigger.TriggerType = DOOR_WELD;
|
||||
NewTrigger.bIsActivated = !theEntity->IsLockedByMaster();
|
||||
|
||||
DoorRef->TriggerEnts.push_back(NewTrigger);
|
||||
}
|
||||
END_FOR_ALL_ENTITIES(kwsWeldableClassName)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void UTIL_PopulateWeldableObstacles()
|
||||
{
|
||||
UTIL_ClearWeldablesData();
|
||||
|
@ -7120,8 +7078,33 @@ void UTIL_UpdateDoorTriggers(nav_door* Door)
|
|||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
it->bIsActivated = (it->ToggleEnt) ? !it->ToggleEnt->IsLockedByMaster() : true;
|
||||
|
||||
if (FStrEq(STRING(it->Edict->v.target), STRING(Door->DoorEdict->v.targetname)))
|
||||
{
|
||||
it->bIsActivated = (it->ToggleEnt) ? !it->ToggleEnt->IsLockedByMaster() : true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Weldables and breakables can't be "deactivated" so assume they are always actived
|
||||
if (it->TriggerType == DOOR_WELD || it->TriggerType == DOOR_BREAK)
|
||||
{
|
||||
it->bIsActivated = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
CBaseEntity* ActivationTarget = UTIL_FindEntityByString(NULL, "targetname", STRING(it->Edict->v.target));
|
||||
|
||||
if (!ActivationTarget)
|
||||
{
|
||||
it->bIsActivated = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
const char* classname = STRING(ActivationTarget->pev->classname);
|
||||
it->bIsActivated = (FStrEq(classname, "multi_manager") || FStrEq(classname, "trigger_changetarget") || FStrEq(classname, "multisource"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (it->bIsActivated)
|
||||
{
|
||||
|
|
|
@ -76,7 +76,8 @@ enum DoorActivationType
|
|||
DOOR_TRIGGER,// Door activated by touching a trigger_once or trigger_multiple
|
||||
DOOR_BUTTON, // Door activated by pressing a button
|
||||
DOOR_WELD, // Door activated by welding something
|
||||
DOOR_SHOOT // Door activated by being shot
|
||||
DOOR_SHOOT, // Door activated by being shot
|
||||
DOOR_BREAK // Door activated by breaking something
|
||||
};
|
||||
|
||||
typedef struct _DOOR_TRIGGER
|
||||
|
@ -173,9 +174,6 @@ void LerkUpdateBotMoveProfile(AvHAIPlayer* pBot, BotMoveStyle MoveStyle);
|
|||
void FadeUpdateBotMoveProfile(AvHAIPlayer* pBot, BotMoveStyle MoveStyle);
|
||||
void OnosUpdateBotMoveProfile(AvHAIPlayer* pBot, BotMoveStyle MoveStyle);
|
||||
|
||||
// FUTURE FEATURE: Will eventually link a door to the trigger than opens it
|
||||
void UTIL_LinkTriggerToDoor(const edict_t* DoorEdict, nav_door* DoorRef);
|
||||
|
||||
// Finds any random point on the navmesh that is relevant for the bot. Returns ZERO_VECTOR if none found
|
||||
Vector UTIL_GetRandomPointOnNavmesh(const AvHAIPlayer* pBot);
|
||||
|
||||
|
|
|
@ -513,7 +513,7 @@ void BotAttackTarget(AvHAIPlayer* pBot, edict_t* Target)
|
|||
return;
|
||||
}
|
||||
|
||||
Vector AttackPoint = Target->v.origin;
|
||||
Vector AttackPoint = (IsEdictPlayer(Target) || IsEdictStructure(Target)) ? Target->v.origin : UTIL_GetButtonFloorLocation(pBot->Edict->v.origin, Target);
|
||||
|
||||
if (StructureType == STRUCTURE_ALIEN_HIVE)
|
||||
{
|
||||
|
@ -540,6 +540,13 @@ void BotAttackTarget(AvHAIPlayer* pBot, edict_t* Target)
|
|||
|
||||
if (AttackResult == ATTACK_BLOCKED)
|
||||
{
|
||||
if (!(IsEdictPlayer(Target) && !IsEdictStructure(Target)))
|
||||
{
|
||||
Vector AttackPoint = UTIL_GetButtonFloorLocation(pBot->Edict->v.origin, Target);
|
||||
MoveTo(pBot, AttackPoint, MOVESTYLE_NORMAL, WeaponRange);
|
||||
return;
|
||||
}
|
||||
|
||||
if (vIsZero(pBot->BotNavInfo.ActualMoveDestination) || UTIL_TraceEntity(pBot->Edict, pBot->BotNavInfo.ActualMoveDestination + Vector(0.0f, 0.0f, 32.0f), UTIL_GetCentreOfEntity(Target)) != Target)
|
||||
{
|
||||
Vector NewAttackLocation = ZERO_VECTOR;
|
||||
|
@ -1495,7 +1502,7 @@ void DroneThink(AvHAIPlayer* pBot)
|
|||
BotProgressTask(pBot, &pBot->PrimaryBotTask);
|
||||
}
|
||||
|
||||
AIDEBUG_DrawBotPath(pBot);
|
||||
//AIDEBUG_DrawBotPath(pBot);
|
||||
}
|
||||
|
||||
void TestNavThink(AvHAIPlayer* pBot)
|
||||
|
|
|
@ -641,17 +641,29 @@ void AIMGR_ResetRound()
|
|||
|
||||
void AIMGR_ClearBotData()
|
||||
{
|
||||
// We shouldn't have any bots in the server when this is called, but this ensures no bots end up "orphans" and no longer tracked by the system
|
||||
for (auto it = ActiveAIPlayers.begin(); it != ActiveAIPlayers.end();)
|
||||
// We have to be careful here, depending on how the nav data is being unloaded, there could be stale references in the ActiveAIPlayers list.
|
||||
for (int i = 1; i <= gpGlobals->maxClients; i++)
|
||||
{
|
||||
if (!FNullEnt(it->Edict) && it->Player)
|
||||
{
|
||||
it->Player->Kick();
|
||||
}
|
||||
edict_t* PlayerEdict = INDEXENT(i);
|
||||
|
||||
it = ActiveAIPlayers.erase(it);
|
||||
if (!FNullEnt(PlayerEdict) && !PlayerEdict->free && (PlayerEdict->v.flags & FL_FAKECLIENT))
|
||||
{
|
||||
for (auto it = ActiveAIPlayers.begin(); it != ActiveAIPlayers.end();)
|
||||
{
|
||||
if (it->Edict == PlayerEdict && it->Player)
|
||||
{
|
||||
it->Player->Kick();
|
||||
it = ActiveAIPlayers.erase(it);
|
||||
}
|
||||
else
|
||||
{
|
||||
it++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We shouldn't have any bots in the server when this is called, but this ensures no bots end up "orphans" and no longer tracked by the system
|
||||
ActiveAIPlayers.clear();
|
||||
}
|
||||
|
||||
|
|
|
@ -362,6 +362,8 @@ bool AITASK_IsMoveTaskStillValid(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
|||
{
|
||||
if (!Task->TaskLocation) { return false; }
|
||||
|
||||
if (pBot->BotNavInfo.NavProfile.bFlyingProfile && vEquals(pBot->Edict->v.origin, Task->TaskLocation, 50.0f)) { return false; }
|
||||
|
||||
return (vDist2DSq(pBot->Edict->v.origin, Task->TaskLocation) > sqrf(max_player_use_reach) || !UTIL_PointIsDirectlyReachable(pBot->CurrentFloorPosition, Task->TaskLocation));
|
||||
}
|
||||
|
||||
|
@ -454,18 +456,18 @@ bool AITASK_IsWeaponPickupTaskStillValid(AvHAIPlayer* pBot, AvHAIPlayerTask* Tas
|
|||
|
||||
bool AITASK_IsAttackTaskStillValid(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
||||
{
|
||||
if (FNullEnt(Task->TaskTarget) || vIsZero(Task->TaskTarget->v.origin)) { return false; }
|
||||
if (FNullEnt(Task->TaskTarget) || (vIsZero(Task->TaskTarget->v.origin) && vIsZero(Task->TaskLocation))) { return false; }
|
||||
|
||||
if ((Task->TaskTarget->v.effects & EF_NODRAW) || (Task->TaskTarget->v.deadflag != DEAD_NO)) { return false; }
|
||||
|
||||
if (!UTIL_IsBuildableStructureStillReachable(pBot, Task->TaskTarget)) { return false; }
|
||||
if (IsEdictStructure(Task->TaskTarget) && !UTIL_IsBuildableStructureStillReachable(pBot, Task->TaskTarget)) { return false; }
|
||||
|
||||
if (IsPlayerSkulk(pBot->Edict))
|
||||
{
|
||||
if (UTIL_IsStructureElectrified(Task->TaskTarget)) { return false; }
|
||||
}
|
||||
|
||||
if (IsPlayerGorge(pBot->Edict) && !PlayerHasWeapon(pBot->Player, WEAPON_GORGE_BILEBOMB)) { return false; }
|
||||
if (IsPlayerGorge(pBot->Edict) && (Task->TaskTarget->v.health > 100 && !PlayerHasWeapon(pBot->Player, WEAPON_GORGE_BILEBOMB))) { return false; }
|
||||
|
||||
AvHAIDeployableStructureType StructureType = GetStructureTypeFromEdict(Task->TaskTarget);
|
||||
|
||||
|
@ -1567,8 +1569,53 @@ void BotProgressAttackTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
|||
return;
|
||||
}
|
||||
|
||||
AvHAIWeapon Weapon = WEAPON_INVALID;
|
||||
|
||||
BotAttackTarget(pBot, Task->TaskTarget);
|
||||
if (IsPlayerMarine(pBot->Edict))
|
||||
{
|
||||
Weapon = BotMarineChooseBestWeaponForStructure(pBot, Task->TaskTarget);
|
||||
}
|
||||
else
|
||||
{
|
||||
Weapon = BotAlienChooseBestWeaponForStructure(pBot, Task->TaskTarget);
|
||||
}
|
||||
|
||||
BotAttackResult AttackResult = PerformAttackLOSCheck(pBot, Weapon, Task->TaskTarget);
|
||||
|
||||
if (AttackResult == ATTACK_SUCCESS)
|
||||
{
|
||||
// If we were ducking before then keep ducking
|
||||
if (pBot->Edict->v.oldbuttons & IN_DUCK)
|
||||
{
|
||||
pBot->Button |= IN_DUCK;
|
||||
}
|
||||
|
||||
BotShootTarget(pBot, Weapon, Task->TaskTarget);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!vIsZero(Task->TaskLocation))
|
||||
{
|
||||
MoveTo(pBot, Task->TaskLocation, MOVESTYLE_NORMAL, max_player_use_reach);
|
||||
return;
|
||||
}
|
||||
|
||||
Vector AttackLocation = (IsEdictPlayer(Task->TaskTarget) || IsEdictStructure(Task->TaskTarget)) ? Task->TaskTarget->v.origin : UTIL_GetButtonFloorLocation(pBot->Edict->v.origin, Task->TaskTarget);
|
||||
|
||||
if (vIsZero(AttackLocation))
|
||||
{
|
||||
AttackLocation = Task->TaskTarget->v.origin;
|
||||
}
|
||||
|
||||
float WeaponRange = GetMaxIdealWeaponRange(Weapon);
|
||||
|
||||
Vector NewTaskLocation = FindClosestNavigablePointToDestination(pBot->BotNavInfo.NavProfile, pBot->CurrentFloorPosition, AttackLocation, WeaponRange);
|
||||
|
||||
Task->TaskLocation = (!vIsZero(NewTaskLocation)) ? NewTaskLocation : AttackLocation;
|
||||
|
||||
MoveTo(pBot, Task->TaskLocation, MOVESTYLE_NORMAL, max_player_use_reach);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -9502,7 +9502,7 @@ void AvHPlayer::UpdateAlienUI()
|
|||
currentMask |= 0x80;
|
||||
|
||||
int teamMask=0;
|
||||
AvHEntityHierarchy& theEntHier=GetGameRules()->GetEntityHierarchy(this->GetTeam());
|
||||
AvHEntityHierarchy& theEntHier=GetGameRules()->GetEntityHierarchy(this->GetTeam(true));
|
||||
teamMask |= ( theEntHier.GetNumSensory() & 0x3 );
|
||||
teamMask <<= 2;
|
||||
teamMask |= ( theEntHier.GetNumDefense() & 0x3 );
|
||||
|
|
Loading…
Reference in a new issue