Added lift and moving platform support

This commit is contained in:
RGreenlees 2023-11-25 11:10:52 +00:00 committed by pierow
parent 80b9c4035d
commit 6ebe05483c
8 changed files with 477 additions and 93 deletions

View file

@ -290,6 +290,7 @@ void AIDEBUG_DrawPath(vector<bot_path_node>& path, float DrawTime)
UTIL_DrawLine(INDEXENT(1), FromLoc, ToLoc, DrawTime, 255, 255, 0);
break;
case SAMPLE_POLYFLAGS_LADDER:
case SAMPLE_POLYFLAGS_LIFT:
UTIL_DrawLine(INDEXENT(1), FromLoc, ToLoc, DrawTime, 0, 0, 255);
break;
case SAMPLE_POLYFLAGS_WALLCLIMB:

View file

@ -2030,6 +2030,8 @@ bool HasBotReachedPathPoint(const AvHAIPlayer* pBot)
case SAMPLE_POLYFLAGS_TEAM1PHASEGATE:
case SAMPLE_POLYFLAGS_TEAM2PHASEGATE:
return (vDist2DSq(pBot->CurrentFloorPosition, MoveTo) < sqrf(32.0f));
case SAMPLE_POLYFLAGS_LIFT:
return bAtOrPastDestination;
default:
return (bAtOrPastDestination && UTIL_QuickTrace(pEdict, pEdict->v.origin, MoveTo));
}
@ -2141,7 +2143,7 @@ void CheckAndHandleDoorObstruction(AvHAIPlayer* pBot)
DoorTrigger* Trigger = UTIL_GetNearestDoorTrigger(pBot->Edict->v.origin, Door, nullptr);
if (Trigger)
if (Trigger && Trigger->NextActivationTime < gpGlobals->time)
{
if (Trigger->TriggerType == DOOR_BUTTON)
{
@ -2673,6 +2675,39 @@ bool UTIL_IsPathBlockedByDoor(const Vector StartLoc, const Vector EndLoc, edict_
return true;
}
DoorTrigger* UTIL_GetNearestDoorTriggerFromLift(edict_t* LiftEdict, nav_door* Door, CBaseEntity* IgnoreTrigger)
{
if (!Door) { return nullptr; }
if (Door->TriggerEnts.size() == 0) { return nullptr; }
DoorTrigger* NearestTrigger = nullptr;
float NearestDist = 0.0f;
for (auto it = Door->TriggerEnts.begin(); it != Door->TriggerEnts.end(); it++)
{
if (!FNullEnt(it->Edict) && it->Entity != IgnoreTrigger && it->bIsActivated)
{
Vector ButtonLocation = UTIL_GetClosestPointOnEntityToLocation(UTIL_GetCentreOfEntity(LiftEdict), it->Edict);
Vector NearestPointOnLift = UTIL_GetClosestPointOnEntityToLocation(ButtonLocation, LiftEdict);
float thisDist = vDist3DSq(ButtonLocation, NearestPointOnLift);
if (thisDist < sqrf(64.0f))
{
if (!NearestTrigger || thisDist < NearestDist)
{
NearestTrigger = &(*it);
NearestDist = thisDist;
}
}
}
}
return NearestTrigger;
}
DoorTrigger* UTIL_GetNearestDoorTrigger(const Vector Location, nav_door* Door, CBaseEntity* IgnoreTrigger)
{
if (!Door) { return nullptr; }
@ -2690,9 +2725,9 @@ DoorTrigger* UTIL_GetNearestDoorTrigger(const Vector Location, nav_door* Door, C
{
Vector ButtonLocation = UTIL_GetButtonFloorLocation(Location, it->Edict);
if (!UTIL_IsPathBlockedByDoor(Location, ButtonLocation, Door->DoorEdict))
if ((true || !UTIL_IsPathBlockedByDoor(Location, ButtonLocation, Door->DoorEdict)) && UTIL_PointIsReachable(GetBaseNavProfile(MARINE_BASE_NAV_PROFILE), Location, ButtonLocation, 64.0f))
{
float ThisDist = vDist3DSq(DoorLocation, ButtonLocation);
float ThisDist = vDist3DSq(Location, ButtonLocation);
if (!NearestTrigger || ThisDist < NearestDist)
{
@ -2854,6 +2889,9 @@ void NewMove(AvHAIPlayer* pBot)
case SAMPLE_POLYFLAGS_TEAM2PHASEGATE:
PhaseGateMove(pBot, MoveFrom, MoveTo);
break;
case SAMPLE_POLYFLAGS_LIFT:
LiftMove(pBot, MoveFrom, MoveTo);
break;
default:
GroundMove(pBot, MoveFrom, MoveTo);
break;
@ -2878,7 +2916,10 @@ void NewMove(AvHAIPlayer* pBot)
// While moving, check to make sure we're not obstructed by a func_breakable, e.g. vent or window.
CheckAndHandleBreakableObstruction(pBot, MoveFrom, MoveTo);
CheckAndHandleDoorObstruction(pBot);
if (CurrentNavFlags != SAMPLE_POLYFLAGS_LIFT)
{
CheckAndHandleDoorObstruction(pBot);
}
}
@ -3437,6 +3478,240 @@ void SkulkLadderMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector En
}
bool UTIL_TriggerHasBeenRecentlyActivated(edict_t* TriggerEntity)
{
return true;
}
DoorTrigger* UTIL_GetDoorTriggerByEntity(edict_t* TriggerEntity)
{
for (auto door = NavDoors.begin(); door != NavDoors.end(); door++)
{
for (auto trig = door->TriggerEnts.begin(); trig != door->TriggerEnts.end(); trig++)
{
if (trig->Edict == TriggerEntity) { return &(*trig); }
}
}
return nullptr;
}
void LiftMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector EndPoint)
{
nav_door* NearestLift = UTIL_GetClosestLiftToPoints(StartPoint, EndPoint);
if (!NearestLift)
{
GroundMove(pBot, StartPoint, EndPoint);
return;
}
UTIL_DrawLine(INDEXENT(1), pBot->Edict->v.origin, UTIL_GetCentreOfEntity(NearestLift->DoorEdict));
Vector LiftPosition = UTIL_GetCentreOfEntity(NearestLift->DoorEdict);
pBot->desiredMovementDir = ZERO_VECTOR;
Vector DesiredStartStop = ZERO_VECTOR;
Vector DesiredEndStop = ZERO_VECTOR;
float minStartDist = 0.0f;
float minEndDist = 0.0f;
// Find the desired stop point for us to get onto the lift
for (auto it = NearestLift->StopPoints.begin(); it != NearestLift->StopPoints.end(); it++)
{
float thisStartDist = vDist3DSq(*it, StartPoint);
float thisEndDist = vDist3DSq(*it, EndPoint);
if (vIsZero(DesiredStartStop) || thisStartDist < minStartDist)
{
DesiredStartStop = *it;
minStartDist = thisStartDist;
}
if (vIsZero(DesiredEndStop) || thisEndDist < minEndDist)
{
DesiredEndStop = *it;
minEndDist = thisEndDist;
}
}
bool bIsLiftMoving = (NearestLift->DoorEdict->v.velocity.Length() > 0.0f);
bool bIsLiftMovingToStart = bIsLiftMoving && (vDist3DSq(NearestLift->DoorEntity->m_vecFinalDest, DesiredStartStop) < sqrf(50.0f));
bool bIsLiftMovingToEnd = bIsLiftMoving && (vDist3DSq(NearestLift->DoorEntity->m_vecFinalDest, DesiredEndStop) < sqrf(50.0f));
bool bIsLiftAtOrNearStart = (vDist3DSq(LiftPosition, DesiredStartStop) < sqrf(50.0f));
bool bIsLiftAtOrNearEnd = (vDist3DSq(LiftPosition, DesiredEndStop) < sqrf(50.0f));
bool bIsOnLift = (pBot->Edict->v.groundentity == NearestLift->DoorEdict);
bool bWaitingToEmbark = (!bIsOnLift && vDist3DSq(pBot->Edict->v.origin, StartPoint) < vDist3DSq(pBot->Edict->v.origin, EndPoint)) || (bIsOnLift && !bIsLiftMoving && bIsLiftAtOrNearStart);
// Do nothing if we're on a moving lift
if (bIsLiftMoving && bIsOnLift) { return; }
// if we've reached our stop, or we can directly get to the end point. Move straight there
Vector BotNavPosition = UTIL_ProjectPointToNavmesh(pBot->CollisionHullBottomLocation);
BotNavPosition = (vIsZero(BotNavPosition)) ? pBot->CollisionHullBottomLocation : BotNavPosition;
if ((bIsOnLift && !bIsLiftMoving && bIsLiftAtOrNearEnd) || UTIL_PointIsDirectlyReachable(BotNavPosition, EndPoint))
{
pBot->desiredMovementDir = UTIL_GetVectorNormal2D(EndPoint - pBot->CollisionHullBottomLocation);
return;
}
// We must be either waiting to embark, or we've stopped elsewhere on our journey and need to get the lift moving again
// Lift is leaving without us! Get on it quick
if (bIsLiftMoving && !bIsLiftMovingToStart && bIsLiftAtOrNearStart && !bIsOnLift)
{
pBot->desiredMovementDir = UTIL_GetVectorNormal2D(LiftPosition - pBot->CollisionHullBottomLocation);
BotJump(pBot);
return;
}
if (bIsLiftMoving)
{
AITASK_SetMoveTask(pBot, &pBot->BotNavInfo.MovementTask, StartPoint, true);
return;
}
// Lift is stopped somewhere else, summon it
if (!bIsLiftMoving)
{
DoorTrigger* NearestLiftTrigger = nullptr;
if (bIsLiftAtOrNearStart)
{
float NearestDist = 0.0f;
for (auto it = NearestLift->TriggerEnts.begin(); it != NearestLift->TriggerEnts.end(); it++)
{
if (!FNullEnt(it->Edict) && it->bIsActivated)
{
Vector CheckLocation = UTIL_GetCentreOfEntity(NearestLift->DoorEdict);
CheckLocation.z = pBot->Edict->v.origin.z;
Vector ButtonLocation = UTIL_GetClosestPointOnEntityToLocation(CheckLocation, it->Edict);
Vector NearestPointOnLift = UTIL_GetClosestPointOnEntityToLocation(ButtonLocation, NearestLift->DoorEdict);
NearestPointOnLift.z = pBot->Edict->v.origin.z;
float thisDist = vDist3DSq(ButtonLocation, NearestPointOnLift);
if (thisDist < sqrf(64.0f))
{
if (!NearestLiftTrigger || thisDist < NearestDist)
{
NearestLiftTrigger = &(*it);
NearestDist = thisDist;
}
}
}
}
}
if (!NearestLiftTrigger)
{
NearestLiftTrigger = UTIL_GetNearestDoorTrigger(pBot->Edict->v.origin, NearestLift, nullptr);
}
if (NearestLiftTrigger)
{
if (gpGlobals->time < NearestLiftTrigger->NextActivationTime || !(NearestLift->DoorEdict->v.spawnflags & SF_TRAIN_WAIT_RETRIGGER) || (NearestLift->DoorEntity && NearestLift->DoorEntity->m_flWait > 0.0f))
{
if (!bIsOnLift && vDist2DSq(pBot->Edict->v.origin, StartPoint) > sqrf(50.0f) && !bIsLiftAtOrNearStart)
{
AITASK_SetMoveTask(pBot, &pBot->BotNavInfo.MovementTask, StartPoint, true);
}
else
{
if (!bIsOnLift && bIsLiftAtOrNearStart)
{
pBot->desiredMovementDir = UTIL_GetVectorNormal2D(LiftPosition - StartPoint);
}
}
return;
}
if (bIsLiftAtOrNearStart)
{
Vector ButtonFloorLocation = UTIL_GetClosestPointOnEntityToLocation(pBot->Edict->v.origin, NearestLiftTrigger->Edict);
Vector NearestPointOnLiftToButton = UTIL_GetClosestPointOnEntityToLocation(ButtonFloorLocation, NearestLift->DoorEdict);
bool ButtonReachableFromLift = !vIsZero(ButtonFloorLocation) && (vDist2DSq(ButtonFloorLocation, NearestPointOnLiftToButton) <= sqrf(64.0f));
if (ButtonReachableFromLift)
{
UTIL_DrawLine(INDEXENT(1), pBot->Edict->v.origin, ButtonFloorLocation, 255, 255, 0);
if (IsPlayerInUseRange(pBot->Edict, NearestLiftTrigger->Edict))
{
BotUseObject(pBot, NearestLiftTrigger->Edict, false);
return;
}
if (!bIsOnLift)
{
pBot->desiredMovementDir = UTIL_GetVectorNormal2D(LiftPosition - pBot->Edict->v.origin);
return;
}
else
{
pBot->desiredMovementDir = UTIL_GetVectorNormal2D(ButtonFloorLocation - pBot->Edict->v.origin);
return;
}
}
}
if (NearestLiftTrigger->TriggerType == DOOR_BUTTON)
{
Vector UseLocation = UTIL_GetButtonFloorLocation(pBot->Edict->v.origin, NearestLiftTrigger->Edict);
AITASK_SetUseTask(pBot, &pBot->BotNavInfo.MovementTask, NearestLiftTrigger->Edict, UseLocation, true);
UTIL_DrawLine(INDEXENT(1), pBot->Edict->v.origin, UTIL_GetCentreOfEntity(NearestLiftTrigger->Edict), 10.0f, 255, 255, 0);
UTIL_DrawLine(INDEXENT(1), pBot->Edict->v.origin, UseLocation, 10.0f, 255, 0, 0);
}
else if (NearestLiftTrigger->TriggerType == DOOR_TRIGGER)
{
AITASK_SetTouchTask(pBot, &pBot->BotNavInfo.MovementTask, NearestLiftTrigger->Edict, true);
}
else if (NearestLiftTrigger->TriggerType == DOOR_WELD)
{
AITASK_SetWeldTask(pBot, &pBot->BotNavInfo.MovementTask, NearestLiftTrigger->Edict, true);
}
else if (NearestLiftTrigger->TriggerType == DOOR_BREAK)
{
AITASK_SetAttackTask(pBot, &pBot->BotNavInfo.MovementTask, NearestLiftTrigger->Edict, true);
}
return;
}
else
{
if (!bIsOnLift && vDist2DSq(pBot->Edict->v.origin, StartPoint) > sqrf(50.0f) && !bIsLiftAtOrNearStart)
{
AITASK_SetMoveTask(pBot, &pBot->BotNavInfo.MovementTask, StartPoint, true);
}
else
{
if (!bIsOnLift && bIsLiftAtOrNearStart)
{
pBot->desiredMovementDir = UTIL_GetVectorNormal2D(LiftPosition - StartPoint);
}
}
}
return;
}
}
void PhaseGateMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector EndPoint)
{
DeployableSearchFilter PGFilter;
@ -5028,7 +5303,7 @@ bool MoveTo(AvHAIPlayer* pBot, const Vector Destination, const BotMoveStyle Move
return false;
}
PathFindingStatus = FindPathClosestToPoint(pBot, pBot->BotNavInfo.MoveStyle, pBot->CurrentFloorPosition, ValidNavmeshPoint, BotNavInfo->CurrentPath, MaxAcceptableDist);
PathFindingStatus = FindPathClosestToPoint(pBot, pBot->BotNavInfo.MoveStyle, pBot->CollisionHullBottomLocation, ValidNavmeshPoint, BotNavInfo->CurrentPath, MaxAcceptableDist);
}
if (dtStatusSucceed(PathFindingStatus))
@ -5620,15 +5895,6 @@ Vector UTIL_ProjectPointToNavmesh(const Vector Location)
Vector PointToProject = Location;
int PointContents = UTIL_PointContents(Location);
if (PointContents != CONTENTS_SOLID && PointContents != CONTENTS_LADDER)
{
Vector TraceHit = UTIL_GetTraceHitLocation(Location + Vector(0.0f, 0.0f, 1.0f), Location - Vector(0.0f, 0.0f, 1000.0f));
PointToProject = (TraceHit != g_vecZero) ? TraceHit : Location;
}
float pCheckLoc[3] = { PointToProject.x, PointToProject.z, -PointToProject.y };
dtPolyRef FoundPoly;
@ -5643,7 +5909,28 @@ Vector UTIL_ProjectPointToNavmesh(const Vector Location)
}
else
{
return g_vecZero;
int PointContents = UTIL_PointContents(PointToProject);
if (PointContents != CONTENTS_SOLID && PointContents != CONTENTS_LADDER)
{
Vector TraceHit = UTIL_GetTraceHitLocation(PointToProject + Vector(0.0f, 0.0f, 1.0f), PointToProject - Vector(0.0f, 0.0f, 1000.0f));
PointToProject = (TraceHit != g_vecZero) ? TraceHit : Location;
}
float pRecheckLoc[3] = { PointToProject.x, PointToProject.z, -PointToProject.y };
dtStatus successRetry = m_navQuery->findNearestPoly(pRecheckLoc, Extents, m_navFilter, &FoundPoly, NavNearest);
if (FoundPoly > 0 && dtStatusSucceed(success))
{
return Vector(NavNearest[0], -NavNearest[2], NavNearest[1]);
}
else
{
return g_vecZero;
}
}
}
@ -5655,25 +5942,15 @@ Vector UTIL_ProjectPointToNavmesh(const Vector Location, const Vector Extents)
if (!m_navQuery) { return g_vecZero; }
float extents[3] = { Extents.x, Extents.z, Extents.y };
Vector PointToProject = Location;
int PointContents = UTIL_PointContents(Location);
if (PointContents != CONTENTS_SOLID && PointContents != CONTENTS_LADDER)
{
Vector TraceHit = UTIL_GetTraceHitLocation(Location + Vector(0.0f, 0.0f, 1.0f), Location - Vector(0.0f, 0.0f, 1000.0f));
PointToProject = (TraceHit != g_vecZero) ? TraceHit : Location;
}
float pCheckLoc[3] = { PointToProject.x, PointToProject.z, -PointToProject.y };
dtPolyRef FoundPoly;
float NavNearest[3];
float fExtents[3] = { Extents.x, Extents.z, Extents.y };
dtStatus success = m_navQuery->findNearestPoly(pCheckLoc, extents, m_navFilter, &FoundPoly, NavNearest);
dtStatus success = m_navQuery->findNearestPoly(pCheckLoc, fExtents, m_navFilter, &FoundPoly, NavNearest);
if (FoundPoly > 0 && dtStatusSucceed(success))
{
@ -5681,7 +5958,28 @@ Vector UTIL_ProjectPointToNavmesh(const Vector Location, const Vector Extents)
}
else
{
return g_vecZero;
int PointContents = UTIL_PointContents(PointToProject);
if (PointContents != CONTENTS_SOLID && PointContents != CONTENTS_LADDER)
{
Vector TraceHit = UTIL_GetTraceHitLocation(PointToProject + Vector(0.0f, 0.0f, 1.0f), PointToProject - Vector(0.0f, 0.0f, 1000.0f));
PointToProject = (TraceHit != g_vecZero) ? TraceHit : Location;
}
float pRecheckLoc[3] = { PointToProject.x, PointToProject.z, -PointToProject.y };
dtStatus successRetry = m_navQuery->findNearestPoly(pRecheckLoc, fExtents, m_navFilter, &FoundPoly, NavNearest);
if (FoundPoly > 0 && dtStatusSucceed(success))
{
return Vector(NavNearest[0], -NavNearest[2], NavNearest[1]);
}
else
{
return g_vecZero;
}
}
}
@ -5695,15 +5993,6 @@ Vector UTIL_ProjectPointToNavmesh(const Vector Location, const nav_profile &NavP
Vector PointToProject = Location;
int PointContents = UTIL_PointContents(Location);
if (PointContents != CONTENTS_SOLID && PointContents != CONTENTS_LADDER)
{
Vector TraceHit = UTIL_GetTraceHitLocation(Location + Vector(0.0f, 0.0f, 1.0f), Location - Vector(0.0f, 0.0f, 1000.0f));
PointToProject = (TraceHit != g_vecZero) ? TraceHit : Location;
}
float pCheckLoc[3] = { PointToProject.x, PointToProject.z, -PointToProject.y };
dtPolyRef FoundPoly;
@ -5717,7 +6006,28 @@ Vector UTIL_ProjectPointToNavmesh(const Vector Location, const nav_profile &NavP
}
else
{
return g_vecZero;
int PointContents = UTIL_PointContents(PointToProject);
if (PointContents != CONTENTS_SOLID && PointContents != CONTENTS_LADDER)
{
Vector TraceHit = UTIL_GetTraceHitLocation(PointToProject + Vector(0.0f, 0.0f, 1.0f), PointToProject - Vector(0.0f, 0.0f, 1000.0f));
PointToProject = (TraceHit != g_vecZero) ? TraceHit : Location;
}
float pRecheckLoc[3] = { PointToProject.x, PointToProject.z, -PointToProject.y };
dtStatus successRetry = m_navQuery->findNearestPoly(pRecheckLoc, pExtents, m_navFilter, &FoundPoly, NavNearest);
if (FoundPoly > 0 && dtStatusSucceed(success))
{
return Vector(NavNearest[0], -NavNearest[2], NavNearest[1]);
}
else
{
return g_vecZero;
}
}
}
@ -5731,15 +6041,6 @@ Vector UTIL_ProjectPointToNavmesh(const Vector Location, const Vector Extents, c
Vector PointToProject = Location;
int PointContents = UTIL_PointContents(Location);
if (PointContents != CONTENTS_SOLID && PointContents != CONTENTS_LADDER)
{
Vector TraceHit = UTIL_GetTraceHitLocation(Location + Vector(0.0f, 0.0f, 1.0f), Location - Vector(0.0f, 0.0f, 1000.0f));
PointToProject = (TraceHit != g_vecZero) ? TraceHit : Location;
}
float pCheckLoc[3] = { PointToProject.x, PointToProject.z, -PointToProject.y };
dtPolyRef FoundPoly;
@ -5755,7 +6056,28 @@ Vector UTIL_ProjectPointToNavmesh(const Vector Location, const Vector Extents, c
}
else
{
return g_vecZero;
int PointContents = UTIL_PointContents(PointToProject);
if (PointContents != CONTENTS_SOLID && PointContents != CONTENTS_LADDER)
{
Vector TraceHit = UTIL_GetTraceHitLocation(PointToProject + Vector(0.0f, 0.0f, 1.0f), PointToProject - Vector(0.0f, 0.0f, 1000.0f));
PointToProject = (TraceHit != g_vecZero) ? TraceHit : Location;
}
float pRecheckLoc[3] = { PointToProject.x, PointToProject.z, -PointToProject.y };
dtStatus successRetry = m_navQuery->findNearestPoly(pRecheckLoc, fExtents, m_navFilter, &FoundPoly, NavNearest);
if (FoundPoly > 0 && dtStatusSucceed(success))
{
return Vector(NavNearest[0], -NavNearest[2], NavNearest[1]);
}
else
{
return g_vecZero;
}
}
}
@ -7172,6 +7494,20 @@ void UTIL_UpdateDoorTriggers(nav_door* Door)
}
}
float BaseTriggerDelay = (it->ToggleEnt) ? it->ToggleEnt->m_flDelay : 0.0f;
float DoorDelay = Door->DoorEntity->GetDelay();
it->ActivationDelay = BaseTriggerDelay + DoorDelay + 1.0f;
if (it->ToggleEnt && it->ToggleEnt->GetToggleState() != it->LastToggleState)
{
if (it->LastToggleState != TS_GOING_UP && it->LastToggleState != TS_GOING_DOWN)
{
it->NextActivationTime = gpGlobals->time + it->ActivationDelay;
}
it->LastToggleState = (TOGGLE_STATE)it->ToggleEnt->GetToggleState();
}
it++;
}
@ -7230,12 +7566,14 @@ void UTIL_PopulateTrainStopPoints(nav_door* TrainDoor)
if (!StartCorner)
{
// We aren't using path corners, so we're probably a func_plat
TrainDoor->StopPoints.push_back(TrainRef->m_vecPosition1);
TrainDoor->StopPoints.push_back(TrainRef->m_vecPosition2);
TrainDoor->StopPoints.push_back(UTIL_GetCentreOfEntity(TrainDoor->DoorEdict) + TrainRef->m_vecPosition1);
TrainDoor->StopPoints.push_back(UTIL_GetCentreOfEntity(TrainDoor->DoorEdict) + TrainRef->m_vecPosition2);
return;
}
if (StartCorner->pev->spawnflags & SF_TRAIN_WAIT_RETRIGGER)
// If the "door" is a func_train, then a path corner is considered a "stop" if flagged to wait for retrigger, or has a delay associated with it
// Eventually, we probably want to remove this expectation so the bot can use platforms which continuously move
if (StartCorner->pev->spawnflags & SF_TRAIN_WAIT_RETRIGGER || StartCorner->GetDelay() > 0.0f)
{
TrainDoor->StopPoints.push_back(StartCorner->pev->origin);
}
@ -7247,7 +7585,7 @@ void UTIL_PopulateTrainStopPoints(nav_door* TrainDoor)
while (CurrentCorner != NULL && CurrentCorner != StartCorner)
{
// Check if the train stops at this path corner, and if so, add it to the stop points array
if (CurrentCorner->pev->spawnflags & SF_TRAIN_WAIT_RETRIGGER)
if (CurrentCorner->pev->spawnflags & SF_TRAIN_WAIT_RETRIGGER || CurrentCorner->GetDelay() > 0.0f)
{
TrainDoor->StopPoints.push_back(CurrentCorner->pev->origin);
}
@ -7327,8 +7665,8 @@ void UTIL_PopulateDoors()
}
else
{
NewDoor.StopPoints.push_back(ToggleRef->m_vecPosition1);
NewDoor.StopPoints.push_back(ToggleRef->m_vecPosition2);
NewDoor.StopPoints.push_back(UTIL_GetCentreOfEntity(NewDoor.DoorEdict) + ToggleRef->m_vecPosition1);
NewDoor.StopPoints.push_back(UTIL_GetCentreOfEntity(NewDoor.DoorEdict) + ToggleRef->m_vecPosition2);
}
@ -7352,7 +7690,7 @@ nav_door* UTIL_GetNavDoorByEdict(const edict_t* DoorEdict)
}
// TODO: Find the topmost point when open, and topmost point when closed, and see how closely they align to the top and bottom point parameters
nav_door* UTIL_GetClosestLiftToPoints(const Vector TopPoint, const Vector BottomPoint)
nav_door* UTIL_GetClosestLiftToPoints(const Vector StartPoint, const Vector EndPoint)
{
nav_door* Result = nullptr;
@ -7365,8 +7703,8 @@ nav_door* UTIL_GetClosestLiftToPoints(const Vector TopPoint, const Vector Bottom
for (auto stop = it->StopPoints.begin(); stop != it->StopPoints.end(); stop++)
{
distTopPoint = fminf(distTopPoint, vDist3DSq(UTIL_GetClosestPointOnEntityToLocation(TopPoint, it->DoorEdict, *stop), TopPoint));
distBottomPoint = fminf(distBottomPoint, vDist3DSq(UTIL_GetClosestPointOnEntityToLocation(BottomPoint, it->DoorEdict, *stop), BottomPoint));
distTopPoint = fminf(distTopPoint, vDist3DSq(UTIL_GetClosestPointOnEntityToLocation(StartPoint, it->DoorEdict, *stop), StartPoint));
distBottomPoint = fminf(distBottomPoint, vDist3DSq(UTIL_GetClosestPointOnEntityToLocation(EndPoint, it->DoorEdict, *stop), EndPoint));
}
float thisDist = fminf(distTopPoint, distBottomPoint);

View file

@ -89,6 +89,11 @@ typedef struct _DOOR_TRIGGER
DoorActivationType TriggerType = DOOR_NONE;
bool bIsActivated = false;
CBaseEntity* TriggerChangeTargetRef = nullptr;
float ActivationDelay = 0.0f;
float LastActivatedTime = 0.0f;
TOGGLE_STATE LastToggleState = TS_AT_BOTTOM;
float LastNextThink = 0.0f;
float NextActivationTime = 0.0f;
} DoorTrigger;
// Door reference. Not used, but is a future feature to allow bots to track if a door is open or not, and how to open it etc.
@ -244,6 +249,12 @@ void WallClimbMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector EndP
void BlinkClimbMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector EndPoint, float RequiredClimbHeight);
// Called by NewMove, determines the movement direction and inputs required to use a phase gate to reach end point
void PhaseGateMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector EndPoint);
// Called by NewMove, determines the movement direction and inputs required to use a lift to reach an end point
void LiftMove(AvHAIPlayer* pBot, const Vector StartPoint, const Vector EndPoint);
DoorTrigger* UTIL_GetDoorTriggerByEntity(edict_t* TriggerEntity);
bool UTIL_TriggerHasBeenRecentlyActivated(edict_t* TriggerEntity);
// Will check for any func_breakable which might be in the way (e.g. window, vent) and make the bot aim and attack it to break it. Marines will switch to knife to break it.
void CheckAndHandleBreakableObstruction(AvHAIPlayer* pBot, const Vector MoveFrom, const Vector MoveTo);
@ -251,6 +262,7 @@ void CheckAndHandleBreakableObstruction(AvHAIPlayer* pBot, const Vector MoveFrom
void CheckAndHandleDoorObstruction(AvHAIPlayer* pBot);
DoorTrigger* UTIL_GetNearestDoorTrigger(const Vector Location, nav_door* Door, CBaseEntity* IgnoreTrigger);
DoorTrigger* UTIL_GetNearestDoorTriggerFromLift(edict_t* LiftEdict, nav_door* Door, CBaseEntity* IgnoreTrigger);
bool UTIL_IsPathBlockedByDoor(const Vector StartLoc, const Vector EndLoc, edict_t* SearchDoor);
edict_t* UTIL_GetDoorBlockingPathPoint(AvHAIPlayer* pBot, bot_path_node* PathNode, edict_t* SearchDoor);
@ -465,7 +477,7 @@ void UTIL_PopulateWeldableObstacles();
void UTIL_ApplyTempObstaclesToDoor(nav_door* DoorRef, const int Area);
nav_door* UTIL_GetNavDoorByEdict(const edict_t* DoorEdict);
nav_door* UTIL_GetClosestLiftToPoints(const Vector TopPoint, const Vector BottomPoint);
nav_door* UTIL_GetClosestLiftToPoints(const Vector StartPoint, const Vector EndPoint);
Vector UTIL_AdjustPointAwayFromNavWall(const Vector Location, const float MaxDistanceFromWall);

View file

@ -1502,7 +1502,7 @@ void DroneThink(AvHAIPlayer* pBot)
BotProgressTask(pBot, &pBot->PrimaryBotTask);
}
//AIDEBUG_DrawBotPath(pBot);
AIDEBUG_DrawBotPath(pBot);
}
void TestNavThink(AvHAIPlayer* pBot)

View file

@ -552,11 +552,11 @@ bool IsPlayerInUseRange(const edict_t* Player, const edict_t* Target)
{
if (FNullEnt(Player) || FNullEnt(Target)) { return false; }
if (vDist3DSq(Player->v.origin, UTIL_GetCentreOfEntity(Target)) > sqrf(vSize3D(Target->v.size) + vSize3D(Player->v.size))) { return false; }
//if (vDist3DSq(Player->v.origin, UTIL_GetCentreOfEntity(Target)) > sqrf(vSize3D(Target->v.size) + vSize3D(Player->v.size))) { return false; }
CBaseEntity* UseObject = nullptr;
while ((UseObject = UTIL_FindEntityInSphere(UseObject, Player->v.origin, 60.0f)) != NULL)
while ((UseObject = UTIL_FindEntityInSphere(UseObject, Player->v.origin, 64.0f)) != NULL)
{
if (UseObject->edict() == Target) { return true; }
}

View file

@ -104,7 +104,7 @@ float GetPlayerEnergyRegenPerSecond(edict_t* Player);
// Expresses the combined health and armour of a player vs max
float GetPlayerOverallHealthPercent(const edict_t* Player);
// Gets the world position of the player's viewpoint (i.e. camera position)
// Gets the world position of the player's viewpoint (origin + view_ofs)
Vector GetPlayerEyePosition(const edict_t* Player);
// Player's current height based on their player class, can manually specify if you want the crouched height or not

View file

@ -934,7 +934,11 @@ bool AITASK_IsUseTaskStillValid(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
if (!ToggleRef) { return false; }
return ToggleRef->GetToggleState() == TS_AT_BOTTOM;
DoorTrigger* TriggerRef = UTIL_GetDoorTriggerByEntity(Task->TaskTarget);
if (TriggerRef && gpGlobals->time < TriggerRef->NextActivationTime) { return false; }
return ToggleRef->GetToggleState() == TS_AT_BOTTOM || (ToggleRef->GetToggleState() == TS_AT_TOP && (ToggleRef->pev->spawnflags & 32));
}
@ -956,7 +960,12 @@ void BotProgressMoveTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
return;
}
MoveTo(pBot, Task->TaskLocation, MOVESTYLE_NORMAL);
bool bMoveSuccess = MoveTo(pBot, Task->TaskLocation, MOVESTYLE_NORMAL);
if (!bMoveSuccess)
{
MoveDirectlyTo(pBot, Task->TaskLocation);
}
if (IsPlayerMarine(pBot->Edict))
{
@ -998,7 +1007,12 @@ void BotProgressUseTask(AvHAIPlayer* pBot, AvHAIPlayerTask* Task)
}
}
MoveTo(pBot, Task->TaskLocation, MOVESTYLE_NORMAL);
bool bMoveSuccess = MoveTo(pBot, Task->TaskLocation, MOVESTYLE_NORMAL);
if (!bMoveSuccess)
{
MoveDirectlyTo(pBot, Task->TaskLocation);
}
}
}

View file

@ -1450,31 +1450,6 @@ BOOL AvHGamerules::ClientCommand( CBasePlayer *pPlayer, const char *pcmd )
theSuccess = true;
}
else if (FStrEq(pcmd, "tracedoor2"))
{
Vector TraceStart = GetPlayerEyePosition(theAvHPlayer->edict()); // origin + pev->view_ofs
Vector LookDir = UTIL_GetForwardVector(theAvHPlayer->edict()->v.v_angle); // Converts view angles to normalized unit vector
Vector TraceEnd = TraceStart + (LookDir * 1000.0f);
edict_t* TracedEntity = UTIL_TraceEntity(theAvHPlayer->edict(), TraceStart, TraceEnd);
if (!FNullEnt(TracedEntity))
{
nav_door* Door = UTIL_GetNavDoorByEdict(TracedEntity);
if (Door)
{
vector<DoorTrigger> TriggerEnts;
UTIL_PopulateTriggersForEntity2(Door->DoorEdict, TriggerEnts);
bool bThing = true;
}
}
theSuccess = true;
}
else if (FStrEq(pcmd, "tracedoor"))
{
Vector TraceStart = GetPlayerEyePosition(theAvHPlayer->edict()); // origin + pev->view_ofs
@ -1510,17 +1485,61 @@ BOOL AvHGamerules::ClientCommand( CBasePlayer *pPlayer, const char *pcmd )
theSuccess = true;
}
else if (FStrEq(pcmd, "tracelift"))
{
Vector TraceStart = GetPlayerEyePosition(theAvHPlayer->edict()); // origin + pev->view_ofs
Vector LookDir = UTIL_GetForwardVector(theAvHPlayer->edict()->v.v_angle); // Converts view angles to normalized unit vector
Vector TraceEnd = TraceStart + (LookDir * 1000.0f);
edict_t* TracedEntity = UTIL_TraceEntity(theAvHPlayer->edict(), TraceStart, TraceEnd);
if (!FNullEnt(TracedEntity))
{
nav_door* Door = UTIL_GetNavDoorByEdict(TracedEntity);
if (Door)
{
const dtOffMeshConnection* NearestCon = DEBUG_FindNearestOffMeshConnectionToPoint(theAvHPlayer->pev->origin, SAMPLE_POLYFLAGS_LIFT);
if (NearestCon)
{
Vector ConnectionStart = Vector(NearestCon->pos[0], -NearestCon->pos[2], NearestCon->pos[1]);
Vector ConnectionEnd = Vector(NearestCon->pos[3], -NearestCon->pos[5], NearestCon->pos[4]);
UTIL_DrawLine(INDEXENT(1), ConnectionStart, ConnectionEnd, 10.0f);
for (auto stop = Door->StopPoints.begin(); stop != Door->StopPoints.end(); stop++)
{
UTIL_DrawLine(INDEXENT(1), ConnectionStart, *stop, 10.0f, 255, 0, 0);
Vector NearestPointStart = UTIL_GetClosestPointOnEntityToLocation(ConnectionStart, Door->DoorEdict, *stop);
Vector NearestPointEnd = UTIL_GetClosestPointOnEntityToLocation(ConnectionEnd, Door->DoorEdict, *stop);
UTIL_DrawLine(INDEXENT(1), ConnectionStart, NearestPointStart, 10.0f, 255, 255, 0);
UTIL_DrawLine(INDEXENT(1), ConnectionEnd, NearestPointEnd, 10.0f, 0, 0, 255);
}
}
}
}
theSuccess = true;
}
else if (FStrEq(pcmd, "getlift"))
{
const dtOffMeshConnection* NearestCon = DEBUG_FindNearestOffMeshConnectionToPoint(theAvHPlayer->pev->origin, SAMPLE_POLYFLAGS_LIFT);
Vector ConnectionStart = Vector(NearestCon->pos[0], -NearestCon->pos[2], NearestCon->pos[1]);
Vector ConnectionEnd = Vector(NearestCon->pos[3], -NearestCon->pos[5], NearestCon->pos[4]);
if (NearestCon)
{
Vector ConnectionStart = Vector(NearestCon->pos[0], -NearestCon->pos[2], NearestCon->pos[1]);
Vector ConnectionEnd = Vector(NearestCon->pos[3], -NearestCon->pos[5], NearestCon->pos[4]);
nav_door* NearestDoor = UTIL_GetClosestLiftToPoints(ConnectionStart, ConnectionEnd);
UTIL_DrawLine(INDEXENT(1), ConnectionStart, ConnectionEnd, 10.0f, 0, 0, 255);
if (NearestDoor)
{
UTIL_DrawLine(INDEXENT(1), theAvHPlayer->pev->origin, UTIL_GetCentreOfEntity(NearestDoor->DoorEdict), 10.0f, 255, 255, 0);