mirror of
https://github.com/ENSL/NS.git
synced 2025-02-21 11:21:55 +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 );
|
LINK_ENTITY_TO_CLASS( trigger_changetarget, CTriggerChangeTarget );
|
||||||
|
|
||||||
TYPEDESCRIPTION CTriggerChangeTarget::m_SaveData[] =
|
TYPEDESCRIPTION CTriggerChangeTarget::m_SaveData[] =
|
||||||
|
|
|
@ -59,6 +59,26 @@ private:
|
||||||
CMultiManager* Clone(void);
|
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
|
class CLadder : public CBaseTrigger
|
||||||
{
|
{
|
||||||
|
|
|
@ -2333,6 +2333,10 @@ void CheckAndHandleDoorObstruction(AvHAIPlayer* pBot)
|
||||||
{
|
{
|
||||||
AITASK_SetWeldTask(pBot, &pBot->BotNavInfo.MovementTask, Trigger->Edict, true);
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -3227,7 +3231,6 @@ void LadderMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector EndPoin
|
||||||
pBot->Button |= IN_DUCK;
|
pBot->Button |= IN_DUCK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (pBot->Player->IsOnLadder())
|
if (pBot->Player->IsOnLadder())
|
||||||
{
|
{
|
||||||
// We're on the ladder and actively climbing
|
// 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 we're going down the ladder and are approaching it, just keep moving towards it
|
||||||
if (pBot->BotNavInfo.IsOnGround && !bIsGoingUpLadder)
|
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);
|
Vector ApproachDir = UTIL_GetVectorNormal2D(EndPoint - pBot->Edict->v.origin);
|
||||||
|
|
||||||
float Dot = UTIL_GetDotProduct2D(ApproachDir, vForward);
|
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
|
// 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 (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 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; }
|
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);
|
ClosestPointToPath = vClosestPointOnLine(MoveFrom, CurrentMoveDest, pEdict->v.origin);
|
||||||
|
|
||||||
Vector MoveDir = UTIL_GetVectorNormal(CurrentMoveDest - pEdict->v.origin);
|
Vector MoveDir = UTIL_GetVectorNormal(CurrentMoveDest - MoveFrom);
|
||||||
|
|
||||||
Vector ObstacleCheck = pEdict->v.origin + (MoveDir * 32.0f);
|
|
||||||
|
|
||||||
pEdict->v.origin = ClosestPointToPath;
|
|
||||||
|
|
||||||
if (IsBotStuck(pBot, CurrentMoveDest))
|
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);
|
bool bMustHugGround = (CurrentMoveArea == SAMPLE_POLYAREA_CROUCH || NextMoveArea == SAMPLE_POLYAREA_CROUCH);
|
||||||
|
|
||||||
if (!bMustHugGround || MoveFrom.z <= CurrentMoveDest.z)
|
if (!bMustHugGround || MoveFrom.z <= CurrentMoveDest.z)
|
||||||
{
|
{
|
||||||
if (Velocity < sqrf(500.f))
|
if (CurrentSpeed < sqrf(500.f))
|
||||||
{
|
{
|
||||||
if (!(pEdict->v.oldbuttons & IN_JUMP))
|
if (!(pEdict->v.oldbuttons & IN_JUMP))
|
||||||
{
|
{
|
||||||
|
@ -5520,7 +5547,8 @@ void BotFollowSwimPath(AvHAIPlayer* pBot)
|
||||||
|
|
||||||
float WaterDiff = WaterLevel - pEdict->v.origin.z;
|
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);
|
Vector MoveDir = UTIL_GetVectorNormal2D(BotNavInfo->CurrentPathPoint->Location - pEdict->v.origin);
|
||||||
pBot->desiredMovementDir = MoveDir;
|
pBot->desiredMovementDir = MoveDir;
|
||||||
|
@ -5537,7 +5565,15 @@ void BotFollowSwimPath(AvHAIPlayer* pBot)
|
||||||
return;
|
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);
|
CBaseButton* ButtonRef = dynamic_cast<CBaseButton*>(EntityRef);
|
||||||
AvHWeldable* WeldableRef = dynamic_cast<AvHWeldable*>(EntityRef);
|
AvHWeldable* WeldableRef = dynamic_cast<AvHWeldable*>(EntityRef);
|
||||||
CBaseTrigger* TriggerRef = dynamic_cast<CBaseTrigger*>(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);
|
CBaseToggle* ToggleRef = dynamic_cast<CBaseToggle*>(EntityRef);
|
||||||
|
|
||||||
|
@ -6634,6 +6671,10 @@ void UTIL_PopulateTriggersForEntity(edict_t* Entity, vector<DoorTrigger>& Trigge
|
||||||
{
|
{
|
||||||
NewTriggerType = DOOR_WELD;
|
NewTriggerType = DOOR_WELD;
|
||||||
}
|
}
|
||||||
|
else if (BreakableRef)
|
||||||
|
{
|
||||||
|
NewTriggerType = DOOR_BREAK;
|
||||||
|
}
|
||||||
|
|
||||||
DoorTrigger NewTrigger;
|
DoorTrigger NewTrigger;
|
||||||
NewTrigger.Entity = EntityRef;
|
NewTrigger.Entity = EntityRef;
|
||||||
|
@ -6680,11 +6721,11 @@ void UTIL_PopulateTriggersForEntity(edict_t* Entity, vector<DoorTrigger>& Trigge
|
||||||
if (FStrEq(STRING(EnvGlobalRef->m_globalstate), GlobalName))
|
if (FStrEq(STRING(EnvGlobalRef->m_globalstate), GlobalName))
|
||||||
{
|
{
|
||||||
UTIL_PopulateTriggersForEntity(EnvGlobalRef->edict(), TriggerList);
|
UTIL_PopulateTriggersForEntity(EnvGlobalRef->edict(), TriggerList);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* EntityName = STRING(Entity->v.targetname);
|
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)
|
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))
|
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()
|
void UTIL_PopulateWeldableObstacles()
|
||||||
{
|
{
|
||||||
UTIL_ClearWeldablesData();
|
UTIL_ClearWeldablesData();
|
||||||
|
@ -7120,8 +7078,33 @@ void UTIL_UpdateDoorTriggers(nav_door* Door)
|
||||||
continue;
|
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)
|
if (it->bIsActivated)
|
||||||
{
|
{
|
||||||
|
|
|
@ -76,7 +76,8 @@ enum DoorActivationType
|
||||||
DOOR_TRIGGER,// Door activated by touching a trigger_once or trigger_multiple
|
DOOR_TRIGGER,// Door activated by touching a trigger_once or trigger_multiple
|
||||||
DOOR_BUTTON, // Door activated by pressing a button
|
DOOR_BUTTON, // Door activated by pressing a button
|
||||||
DOOR_WELD, // Door activated by welding something
|
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
|
typedef struct _DOOR_TRIGGER
|
||||||
|
@ -173,9 +174,6 @@ void LerkUpdateBotMoveProfile(AvHAIPlayer* pBot, BotMoveStyle MoveStyle);
|
||||||
void FadeUpdateBotMoveProfile(AvHAIPlayer* pBot, BotMoveStyle MoveStyle);
|
void FadeUpdateBotMoveProfile(AvHAIPlayer* pBot, BotMoveStyle MoveStyle);
|
||||||
void OnosUpdateBotMoveProfile(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
|
// 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);
|
Vector UTIL_GetRandomPointOnNavmesh(const AvHAIPlayer* pBot);
|
||||||
|
|
||||||
|
|
|
@ -513,7 +513,7 @@ void BotAttackTarget(AvHAIPlayer* pBot, edict_t* Target)
|
||||||
return;
|
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)
|
if (StructureType == STRUCTURE_ALIEN_HIVE)
|
||||||
{
|
{
|
||||||
|
@ -540,6 +540,13 @@ void BotAttackTarget(AvHAIPlayer* pBot, edict_t* Target)
|
||||||
|
|
||||||
if (AttackResult == ATTACK_BLOCKED)
|
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)
|
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;
|
Vector NewAttackLocation = ZERO_VECTOR;
|
||||||
|
@ -1495,7 +1502,7 @@ void DroneThink(AvHAIPlayer* pBot)
|
||||||
BotProgressTask(pBot, &pBot->PrimaryBotTask);
|
BotProgressTask(pBot, &pBot->PrimaryBotTask);
|
||||||
}
|
}
|
||||||
|
|
||||||
AIDEBUG_DrawBotPath(pBot);
|
//AIDEBUG_DrawBotPath(pBot);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TestNavThink(AvHAIPlayer* pBot)
|
void TestNavThink(AvHAIPlayer* pBot)
|
||||||
|
|
|
@ -641,17 +641,29 @@ void AIMGR_ResetRound()
|
||||||
|
|
||||||
void AIMGR_ClearBotData()
|
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
|
// 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 (auto it = ActiveAIPlayers.begin(); it != ActiveAIPlayers.end();)
|
for (int i = 1; i <= gpGlobals->maxClients; i++)
|
||||||
{
|
{
|
||||||
if (!FNullEnt(it->Edict) && it->Player)
|
edict_t* PlayerEdict = INDEXENT(i);
|
||||||
{
|
|
||||||
it->Player->Kick();
|
|
||||||
}
|
|
||||||
|
|
||||||
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();
|
ActiveAIPlayers.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -362,6 +362,8 @@ bool AITASK_IsMoveTaskStillValid(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
||||||
{
|
{
|
||||||
if (!Task->TaskLocation) { return false; }
|
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));
|
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)
|
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 ((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 (IsPlayerSkulk(pBot->Edict))
|
||||||
{
|
{
|
||||||
if (UTIL_IsStructureElectrified(Task->TaskTarget)) { return false; }
|
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);
|
AvHAIDeployableStructureType StructureType = GetStructureTypeFromEdict(Task->TaskTarget);
|
||||||
|
|
||||||
|
@ -1567,8 +1569,53 @@ void BotProgressAttackTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
|
||||||
return;
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9502,7 +9502,7 @@ void AvHPlayer::UpdateAlienUI()
|
||||||
currentMask |= 0x80;
|
currentMask |= 0x80;
|
||||||
|
|
||||||
int teamMask=0;
|
int teamMask=0;
|
||||||
AvHEntityHierarchy& theEntHier=GetGameRules()->GetEntityHierarchy(this->GetTeam());
|
AvHEntityHierarchy& theEntHier=GetGameRules()->GetEntityHierarchy(this->GetTeam(true));
|
||||||
teamMask |= ( theEntHier.GetNumSensory() & 0x3 );
|
teamMask |= ( theEntHier.GetNumSensory() & 0x3 );
|
||||||
teamMask <<= 2;
|
teamMask <<= 2;
|
||||||
teamMask |= ( theEntHier.GetNumDefense() & 0x3 );
|
teamMask |= ( theEntHier.GetNumDefense() & 0x3 );
|
||||||
|
|
Loading…
Reference in a new issue