diff options
| author | Jørgen P. Tjernø <[email protected]> | 2013-12-02 19:31:46 -0800 |
|---|---|---|
| committer | Jørgen P. Tjernø <[email protected]> | 2013-12-02 19:46:31 -0800 |
| commit | f56bb35301836e56582a575a75864392a0177875 (patch) | |
| tree | de61ddd39de3e7df52759711950b4c288592f0dc /mp/src/game/server/ai_basenpc_movement.cpp | |
| parent | Mark some more files as text. (diff) | |
| download | source-sdk-2013-f56bb35301836e56582a575a75864392a0177875.tar.xz source-sdk-2013-f56bb35301836e56582a575a75864392a0177875.zip | |
Fix line endings. WHAMMY.
Diffstat (limited to 'mp/src/game/server/ai_basenpc_movement.cpp')
| -rw-r--r-- | mp/src/game/server/ai_basenpc_movement.cpp | 998 |
1 files changed, 499 insertions, 499 deletions
diff --git a/mp/src/game/server/ai_basenpc_movement.cpp b/mp/src/game/server/ai_basenpc_movement.cpp index 2697f0af..142b11e2 100644 --- a/mp/src/game/server/ai_basenpc_movement.cpp +++ b/mp/src/game/server/ai_basenpc_movement.cpp @@ -1,499 +1,499 @@ -//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose:
-//
-// $NoKeywords: $
-//=============================================================================//
-
-
-#include "cbase.h"
-
-#include "game.h"
-#include "ndebugoverlay.h"
-
-#include "ai_basenpc.h"
-#include "ai_hull.h"
-#include "ai_node.h"
-#include "ai_motor.h"
-#include "ai_navigator.h"
-#include "ai_hint.h"
-#include "scripted.h"
-
-// memdbgon must be the last include file in a .cpp file!!!
-#include "tier0/memdbgon.h"
-
-//=============================================================================
-// PATHING & HIGHER LEVEL MOVEMENT
-//-----------------------------------------------------------------------------
-
-//-----------------------------------------------------------------------------
-// Purpose: Static debug function to force all selected npcs to go to the
-// given node
-// Input :
-// Output :
-//-----------------------------------------------------------------------------
-void CAI_BaseNPC::ForceSelectedGo(CBaseEntity *pPlayer, const Vector &targetPos, const Vector &traceDir, bool bRun)
-{
- CAI_BaseNPC *npc = gEntList.NextEntByClass( (CAI_BaseNPC *)NULL );
-
- while (npc)
- {
- if (npc->m_debugOverlays & OVERLAY_NPC_SELECTED_BIT)
- {
- Vector chasePosition = targetPos;
- npc->TranslateNavGoal( pPlayer, chasePosition );
- // It it legal to drop me here
- Vector vUpBit = chasePosition;
- vUpBit.z += 1;
-
- trace_t tr;
- AI_TraceHull( chasePosition, vUpBit, npc->GetHullMins(),
- npc->GetHullMaxs(), MASK_NPCSOLID, npc, COLLISION_GROUP_NONE, &tr );
- if (tr.startsolid || tr.fraction != 1.0 )
- {
- NDebugOverlay::BoxAngles(chasePosition, npc->GetHullMins(),
- npc->GetHullMaxs(), npc->GetAbsAngles(), 255,0,0,20,0.5);
- }
-
- npc->m_vecLastPosition = chasePosition;
-
- if (npc->m_hCine != NULL)
- {
- npc->ExitScriptedSequence();
- }
-
- if ( bRun )
- npc->SetSchedule( SCHED_FORCED_GO_RUN );
- else
- npc->SetSchedule( SCHED_FORCED_GO );
- npc->m_flMoveWaitFinished = gpGlobals->curtime;
- }
- npc = gEntList.NextEntByClass(npc);
- }
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Static debug function to make all selected npcs run around
-// Input :
-// Output :
-//-----------------------------------------------------------------------------
-void CAI_BaseNPC::ForceSelectedGoRandom(void)
-{
- CAI_BaseNPC *npc = gEntList.NextEntByClass( (CAI_BaseNPC *)NULL );
-
- while (npc)
- {
- if (npc->m_debugOverlays & OVERLAY_NPC_SELECTED_BIT)
- {
- npc->SetSchedule( SCHED_RUN_RANDOM );
- npc->GetNavigator()->SetMovementActivity(ACT_RUN);
- }
- npc = gEntList.NextEntByClass(npc);
- }
-}
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-bool CAI_BaseNPC::ScheduledMoveToGoalEntity( int scheduleType, CBaseEntity *pGoalEntity, Activity movementActivity )
-{
- if ( m_NPCState == NPC_STATE_NONE )
- {
- // More than likely being grabbed before first think. Set ideal state to prevent schedule stomp
- m_NPCState = m_IdealNPCState;
- }
-
- SetSchedule( scheduleType );
-
- SetGoalEnt( pGoalEntity );
-
- // HACKHACK: Call through TranslateNavGoal to fixup this goal position
- // UNDONE: Remove this and have NPCs that need this functionality fix up paths in the
- // movement system instead of when they are specified.
- AI_NavGoal_t goal(pGoalEntity->GetAbsOrigin(), movementActivity, AIN_DEF_TOLERANCE, AIN_YAW_TO_DEST);
-
- TranslateNavGoal( pGoalEntity, goal.dest );
-
- return GetNavigator()->SetGoal( goal );
-}
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-bool CAI_BaseNPC::ScheduledFollowPath( int scheduleType, CBaseEntity *pPathStart, Activity movementActivity )
-{
- if ( m_NPCState == NPC_STATE_NONE )
- {
- // More than likely being grabbed before first think. Set ideal state to prevent schedule stomp
- m_NPCState = m_IdealNPCState;
- }
-
- SetSchedule( scheduleType );
-
- SetGoalEnt( pPathStart );
-
- // HACKHACK: Call through TranslateNavGoal to fixup this goal position
- AI_NavGoal_t goal(GOALTYPE_PATHCORNER, pPathStart->GetLocalOrigin(), movementActivity, AIN_DEF_TOLERANCE, AIN_YAW_TO_DEST);
-
- TranslateNavGoal( pPathStart, goal.dest );
-
- return GetNavigator()->SetGoal( goal );
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input :
-// Output :
-//-----------------------------------------------------------------------------
-bool CAI_BaseNPC::IsMoving( void )
-{
- return GetNavigator()->IsGoalSet();
-}
-
-
-//-----------------------------------------------------------------------------
-
-bool CAI_BaseNPC::IsCurTaskContinuousMove()
-{
- const Task_t* pTask = GetTask();
-
- // This bit of logic strikes me funny, but the case does exist. (sjb)
- if( !pTask )
- return true;
-
- switch( pTask->iTask )
- {
- case TASK_WAIT_FOR_MOVEMENT:
- case TASK_MOVE_TO_TARGET_RANGE:
- case TASK_MOVE_TO_GOAL_RANGE:
- case TASK_WEAPON_RUN_PATH:
- case TASK_PLAY_SCENE:
- case TASK_RUN_PATH_TIMED:
- case TASK_WALK_PATH_TIMED:
- case TASK_RUN_PATH_FOR_UNITS:
- case TASK_WALK_PATH_FOR_UNITS:
- case TASK_RUN_PATH_FLEE:
- case TASK_WALK_PATH_WITHIN_DIST:
- case TASK_RUN_PATH_WITHIN_DIST:
- return true;
- break;
-
- default:
- return false;
- break;
- }
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose: Used to specify that the NPC has a reason not to use the a navigation node
-// Input :
-// Output :
-//-----------------------------------------------------------------------------
-bool CAI_BaseNPC::IsUnusableNode(int iNodeID, CAI_Hint *pHint)
-{
- if ( m_bHintGroupNavLimiting && m_strHintGroup != NULL_STRING && STRING(m_strHintGroup)[0] != 0 )
- {
- if (!pHint || pHint->GetGroup() != GetHintGroup())
- {
- return true;
- }
- }
- return false;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Checks the validity of the given route's goaltype
-// Input :
-// Output :
-//-----------------------------------------------------------------------------
-bool CAI_BaseNPC::ValidateNavGoal()
-{
- if (GetNavigator()->GetGoalType() == GOALTYPE_COVER)
- {
- // Check if this location will block my enemy's line of sight to me
- if (GetEnemy())
- {
- Activity nCoverActivity = GetCoverActivity( GetHintNode() );
- Vector vCoverLocation = GetNavigator()->GetGoalPos();
-
-
- // For now we have to drop the node to the floor so we can
- // get an accurate postion of the NPC. Should change once Ken checks in
- float floorZ = GetFloorZ(vCoverLocation);
- vCoverLocation.z = floorZ;
-
-
- Vector vEyePos = vCoverLocation + EyeOffset(nCoverActivity);
-
- if (!IsCoverPosition( GetEnemy()->EyePosition(), vEyePos ) )
- {
- TaskFail(FAIL_BAD_PATH_GOAL);
- return false;
- }
- }
- }
- return true;
-}
-
-
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input :
-// Output :
-//-----------------------------------------------------------------------------
-float CAI_BaseNPC::OpenDoorAndWait( CBaseEntity *pDoor )
-{
- float flTravelTime = 0;
-
- //DevMsg( 2, "A door. ");
- if (pDoor && !pDoor->IsLockedByMaster())
- {
- pDoor->Use(this, this, USE_ON, 0.0);
- flTravelTime = pDoor->GetMoveDoneTime();
- if ( pDoor->GetEntityName() != NULL_STRING )
- {
- CBaseEntity *pTarget = NULL;
- for (;;)
- {
- pTarget = gEntList.FindEntityByName( pTarget, pDoor->GetEntityName() );
-
- if ( pTarget != pDoor )
- {
- if ( !pTarget )
- break;
-
- if ( FClassnameIs( pTarget, pDoor->GetClassname() ) )
- {
- pTarget->Use(this, this, USE_ON, 0.0);
- }
- }
- }
- }
- }
-
- return gpGlobals->curtime + flTravelTime;
-}
-
-//-----------------------------------------------------------------------------
-
-bool CAI_BaseNPC::CanStandOn( CBaseEntity *pSurface ) const
-{
- if ( !pSurface->IsAIWalkable() )
- {
- return false;
- }
-
- CAI_Navigator *pNavigator = const_cast<CAI_Navigator *>(GetNavigator());
-
- if ( pNavigator->IsGoalActive() &&
- pSurface == pNavigator->GetGoalTarget() )
- return false;
-
- return BaseClass::CanStandOn( pSurface );
-}
-
-//-----------------------------------------------------------------------------
-
-bool CAI_BaseNPC::IsJumpLegal( const Vector &startPos, const Vector &apex, const Vector &endPos,
- float maxUp, float maxDown, float maxDist ) const
-{
- if ((endPos.z - startPos.z) > maxUp + 0.1)
- return false;
- if ((startPos.z - endPos.z) > maxDown + 0.1)
- return false;
-
- if ((apex.z - startPos.z) > maxUp * 1.25 )
- return false;
-
- float dist = (startPos - endPos).Length();
- if ( dist > maxDist + 0.1)
- return false;
- return true;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Returns true if a reasonable jumping distance
-// Input :
-// Output :
-//-----------------------------------------------------------------------------
-bool CAI_BaseNPC::IsJumpLegal( const Vector &startPos, const Vector &apex, const Vector &endPos ) const
-{
- const float MAX_JUMP_RISE = 80.0f;
- const float MAX_JUMP_DISTANCE = 250.0f;
- const float MAX_JUMP_DROP = 192.0f;
-
- return IsJumpLegal( startPos, apex, endPos, MAX_JUMP_RISE, MAX_JUMP_DROP, MAX_JUMP_DISTANCE );
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Returns a throw velocity from start to end position
-// Input :
-// Output :
-//-----------------------------------------------------------------------------
-Vector CAI_BaseNPC::CalcThrowVelocity(const Vector &startPos, const Vector &endPos, float fGravity, float fArcSize)
-{
- // Get the height I have to throw to get to the target
- float stepHeight = endPos.z - startPos.z;
- float throwHeight = 0;
-
- // -----------------------------------------------------------------
- // Now calcluate the distance to a point halfway between our current
- // and target position. (the apex of our throwing arc)
- // -----------------------------------------------------------------
- Vector targetDir2D = endPos - startPos;
- targetDir2D.z = 0;
-
- float distance = VectorNormalize(targetDir2D);
-
-
- // If jumping up we want to throw a bit higher than the height diff
- if (stepHeight > 0)
- {
- throwHeight = stepHeight + fArcSize;
- }
- else
- {
- throwHeight = fArcSize;
- }
- // Make sure that I at least catch some air
- if (throwHeight < fArcSize)
- {
- throwHeight = fArcSize;
- }
-
-
- // -------------------------------------------------------------
- // calculate the vertical and horizontal launch velocities
- // -------------------------------------------------------------
- float velVert = (float)sqrt(2.0f*fGravity*throwHeight);
-
- float divisor = velVert;
- divisor += (float)sqrt((2.0f*(-fGravity)*(stepHeight-throwHeight)));
-
- float velHorz = (distance * fGravity)/divisor;
-
- // -----------------------------------------------------------
- // Make the horizontal throw vector and add vertical component
- // -----------------------------------------------------------
- Vector throwVel = targetDir2D * velHorz;
- throwVel.z = velVert;
-
- return throwVel;
-}
-
-bool CAI_BaseNPC::ShouldMoveWait()
-{
- return (m_flMoveWaitFinished > gpGlobals->curtime);
-}
-
-float CAI_BaseNPC::GetStepDownMultiplier() const
-{
- return m_pNavigator->GetStepDownMultiplier();
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose: execute any movement this sequence may have
-// Output :
-//-----------------------------------------------------------------------------
-bool CAI_BaseNPC::AutoMovement( CBaseEntity *pTarget, AIMoveTrace_t *pTraceResult )
-{
- return AutoMovement( GetAnimTimeInterval(), pTarget, pTraceResult );
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : flInterval -
-// -
-// *pTraceResult -
-// Output : Returns true on success, false on failure.
-//-----------------------------------------------------------------------------
-bool CAI_BaseNPC::AutoMovement( float flInterval, CBaseEntity *pTarget, AIMoveTrace_t *pTraceResult )
-{
- bool ignored;
- Vector newPos;
- QAngle newAngles;
-
- if (flInterval <= 0.0)
- return true;
-
- m_ScheduleState.bTaskRanAutomovement = true;
-
- if (GetIntervalMovement( flInterval, ignored, newPos, newAngles ))
- {
- // DevMsg( "%.2f : (%.1f) %.1f %.1f %.1f\n", gpGlobals->curtime, (newPos - GetLocalOrigin()).Length(), newPos.x, newPos.y, newAngles.y );
-
- if ( m_hCine )
- {
- m_hCine->ModifyScriptedAutoMovement( &newPos );
- }
-
- if (GetMoveType() == MOVETYPE_STEP)
- {
- if (!(GetFlags() & FL_FLY))
- {
- if ( !pTarget )
- {
- pTarget = GetNavTargetEntity();
- }
-
- return ( GetMotor()->MoveGroundStep( newPos, pTarget, newAngles.y, false, true, pTraceResult ) == AIM_SUCCESS );
- }
- else
- {
- // FIXME: here's no direct interface to a fly motor, plus this needs to support a state where going through the world is okay.
- // FIXME: add callbacks into the script system for validation
- // FIXME: add function on scripts to force only legal movements
- // FIXME: GetIntervalMovement deals in Local space, nor global. Currently now way to communicate that through these interfaces.
- SetLocalOrigin( newPos );
- SetLocalAngles( newAngles );
- return true;
- }
- }
- else if (GetMoveType() == MOVETYPE_FLY)
- {
- Vector dist = newPos - GetLocalOrigin();
-
- VectorScale( dist, 1.0 / flInterval, dist );
-
- SetLocalVelocity( dist );
- return true;
- }
- }
- return false;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: return max 1/10 second rate of turning
-// Input :
-// Output :
-//-----------------------------------------------------------------------------
-
-float CAI_BaseNPC::MaxYawSpeed( void )
-{
- return 45;
-}
-
-//-----------------------------------------------------------------------------
-// Returns the estimate in seconds before we reach our nav goal.
-// -1 means we don't know / haven't calculated it yet.
-//-----------------------------------------------------------------------------
-float CAI_BaseNPC::GetTimeToNavGoal()
-{
- float flDist = GetNavigator()->BuildAndGetPathDistToGoal();
- if ( flDist < 0 )
- {
- return -1.0f;
- }
-
- float flSpeed = GetIdealSpeed();
-
- // FIXME: needs to consider stopping time!
- if (flSpeed > 0 && flDist > 0)
- {
- return flDist / flSpeed;
- }
- return 0.0;
-}
-
-//=============================================================================
+//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +//=============================================================================// + + +#include "cbase.h" + +#include "game.h" +#include "ndebugoverlay.h" + +#include "ai_basenpc.h" +#include "ai_hull.h" +#include "ai_node.h" +#include "ai_motor.h" +#include "ai_navigator.h" +#include "ai_hint.h" +#include "scripted.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +//============================================================================= +// PATHING & HIGHER LEVEL MOVEMENT +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// Purpose: Static debug function to force all selected npcs to go to the +// given node +// Input : +// Output : +//----------------------------------------------------------------------------- +void CAI_BaseNPC::ForceSelectedGo(CBaseEntity *pPlayer, const Vector &targetPos, const Vector &traceDir, bool bRun) +{ + CAI_BaseNPC *npc = gEntList.NextEntByClass( (CAI_BaseNPC *)NULL ); + + while (npc) + { + if (npc->m_debugOverlays & OVERLAY_NPC_SELECTED_BIT) + { + Vector chasePosition = targetPos; + npc->TranslateNavGoal( pPlayer, chasePosition ); + // It it legal to drop me here + Vector vUpBit = chasePosition; + vUpBit.z += 1; + + trace_t tr; + AI_TraceHull( chasePosition, vUpBit, npc->GetHullMins(), + npc->GetHullMaxs(), MASK_NPCSOLID, npc, COLLISION_GROUP_NONE, &tr ); + if (tr.startsolid || tr.fraction != 1.0 ) + { + NDebugOverlay::BoxAngles(chasePosition, npc->GetHullMins(), + npc->GetHullMaxs(), npc->GetAbsAngles(), 255,0,0,20,0.5); + } + + npc->m_vecLastPosition = chasePosition; + + if (npc->m_hCine != NULL) + { + npc->ExitScriptedSequence(); + } + + if ( bRun ) + npc->SetSchedule( SCHED_FORCED_GO_RUN ); + else + npc->SetSchedule( SCHED_FORCED_GO ); + npc->m_flMoveWaitFinished = gpGlobals->curtime; + } + npc = gEntList.NextEntByClass(npc); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Static debug function to make all selected npcs run around +// Input : +// Output : +//----------------------------------------------------------------------------- +void CAI_BaseNPC::ForceSelectedGoRandom(void) +{ + CAI_BaseNPC *npc = gEntList.NextEntByClass( (CAI_BaseNPC *)NULL ); + + while (npc) + { + if (npc->m_debugOverlays & OVERLAY_NPC_SELECTED_BIT) + { + npc->SetSchedule( SCHED_RUN_RANDOM ); + npc->GetNavigator()->SetMovementActivity(ACT_RUN); + } + npc = gEntList.NextEntByClass(npc); + } +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +bool CAI_BaseNPC::ScheduledMoveToGoalEntity( int scheduleType, CBaseEntity *pGoalEntity, Activity movementActivity ) +{ + if ( m_NPCState == NPC_STATE_NONE ) + { + // More than likely being grabbed before first think. Set ideal state to prevent schedule stomp + m_NPCState = m_IdealNPCState; + } + + SetSchedule( scheduleType ); + + SetGoalEnt( pGoalEntity ); + + // HACKHACK: Call through TranslateNavGoal to fixup this goal position + // UNDONE: Remove this and have NPCs that need this functionality fix up paths in the + // movement system instead of when they are specified. + AI_NavGoal_t goal(pGoalEntity->GetAbsOrigin(), movementActivity, AIN_DEF_TOLERANCE, AIN_YAW_TO_DEST); + + TranslateNavGoal( pGoalEntity, goal.dest ); + + return GetNavigator()->SetGoal( goal ); +} + +//----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- +bool CAI_BaseNPC::ScheduledFollowPath( int scheduleType, CBaseEntity *pPathStart, Activity movementActivity ) +{ + if ( m_NPCState == NPC_STATE_NONE ) + { + // More than likely being grabbed before first think. Set ideal state to prevent schedule stomp + m_NPCState = m_IdealNPCState; + } + + SetSchedule( scheduleType ); + + SetGoalEnt( pPathStart ); + + // HACKHACK: Call through TranslateNavGoal to fixup this goal position + AI_NavGoal_t goal(GOALTYPE_PATHCORNER, pPathStart->GetLocalOrigin(), movementActivity, AIN_DEF_TOLERANCE, AIN_YAW_TO_DEST); + + TranslateNavGoal( pPathStart, goal.dest ); + + return GetNavigator()->SetGoal( goal ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : +// Output : +//----------------------------------------------------------------------------- +bool CAI_BaseNPC::IsMoving( void ) +{ + return GetNavigator()->IsGoalSet(); +} + + +//----------------------------------------------------------------------------- + +bool CAI_BaseNPC::IsCurTaskContinuousMove() +{ + const Task_t* pTask = GetTask(); + + // This bit of logic strikes me funny, but the case does exist. (sjb) + if( !pTask ) + return true; + + switch( pTask->iTask ) + { + case TASK_WAIT_FOR_MOVEMENT: + case TASK_MOVE_TO_TARGET_RANGE: + case TASK_MOVE_TO_GOAL_RANGE: + case TASK_WEAPON_RUN_PATH: + case TASK_PLAY_SCENE: + case TASK_RUN_PATH_TIMED: + case TASK_WALK_PATH_TIMED: + case TASK_RUN_PATH_FOR_UNITS: + case TASK_WALK_PATH_FOR_UNITS: + case TASK_RUN_PATH_FLEE: + case TASK_WALK_PATH_WITHIN_DIST: + case TASK_RUN_PATH_WITHIN_DIST: + return true; + break; + + default: + return false; + break; + } +} + + +//----------------------------------------------------------------------------- +// Purpose: Used to specify that the NPC has a reason not to use the a navigation node +// Input : +// Output : +//----------------------------------------------------------------------------- +bool CAI_BaseNPC::IsUnusableNode(int iNodeID, CAI_Hint *pHint) +{ + if ( m_bHintGroupNavLimiting && m_strHintGroup != NULL_STRING && STRING(m_strHintGroup)[0] != 0 ) + { + if (!pHint || pHint->GetGroup() != GetHintGroup()) + { + return true; + } + } + return false; +} + +//----------------------------------------------------------------------------- +// Purpose: Checks the validity of the given route's goaltype +// Input : +// Output : +//----------------------------------------------------------------------------- +bool CAI_BaseNPC::ValidateNavGoal() +{ + if (GetNavigator()->GetGoalType() == GOALTYPE_COVER) + { + // Check if this location will block my enemy's line of sight to me + if (GetEnemy()) + { + Activity nCoverActivity = GetCoverActivity( GetHintNode() ); + Vector vCoverLocation = GetNavigator()->GetGoalPos(); + + + // For now we have to drop the node to the floor so we can + // get an accurate postion of the NPC. Should change once Ken checks in + float floorZ = GetFloorZ(vCoverLocation); + vCoverLocation.z = floorZ; + + + Vector vEyePos = vCoverLocation + EyeOffset(nCoverActivity); + + if (!IsCoverPosition( GetEnemy()->EyePosition(), vEyePos ) ) + { + TaskFail(FAIL_BAD_PATH_GOAL); + return false; + } + } + } + return true; +} + + + +//----------------------------------------------------------------------------- +// Purpose: +// Input : +// Output : +//----------------------------------------------------------------------------- +float CAI_BaseNPC::OpenDoorAndWait( CBaseEntity *pDoor ) +{ + float flTravelTime = 0; + + //DevMsg( 2, "A door. "); + if (pDoor && !pDoor->IsLockedByMaster()) + { + pDoor->Use(this, this, USE_ON, 0.0); + flTravelTime = pDoor->GetMoveDoneTime(); + if ( pDoor->GetEntityName() != NULL_STRING ) + { + CBaseEntity *pTarget = NULL; + for (;;) + { + pTarget = gEntList.FindEntityByName( pTarget, pDoor->GetEntityName() ); + + if ( pTarget != pDoor ) + { + if ( !pTarget ) + break; + + if ( FClassnameIs( pTarget, pDoor->GetClassname() ) ) + { + pTarget->Use(this, this, USE_ON, 0.0); + } + } + } + } + } + + return gpGlobals->curtime + flTravelTime; +} + +//----------------------------------------------------------------------------- + +bool CAI_BaseNPC::CanStandOn( CBaseEntity *pSurface ) const +{ + if ( !pSurface->IsAIWalkable() ) + { + return false; + } + + CAI_Navigator *pNavigator = const_cast<CAI_Navigator *>(GetNavigator()); + + if ( pNavigator->IsGoalActive() && + pSurface == pNavigator->GetGoalTarget() ) + return false; + + return BaseClass::CanStandOn( pSurface ); +} + +//----------------------------------------------------------------------------- + +bool CAI_BaseNPC::IsJumpLegal( const Vector &startPos, const Vector &apex, const Vector &endPos, + float maxUp, float maxDown, float maxDist ) const +{ + if ((endPos.z - startPos.z) > maxUp + 0.1) + return false; + if ((startPos.z - endPos.z) > maxDown + 0.1) + return false; + + if ((apex.z - startPos.z) > maxUp * 1.25 ) + return false; + + float dist = (startPos - endPos).Length(); + if ( dist > maxDist + 0.1) + return false; + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: Returns true if a reasonable jumping distance +// Input : +// Output : +//----------------------------------------------------------------------------- +bool CAI_BaseNPC::IsJumpLegal( const Vector &startPos, const Vector &apex, const Vector &endPos ) const +{ + const float MAX_JUMP_RISE = 80.0f; + const float MAX_JUMP_DISTANCE = 250.0f; + const float MAX_JUMP_DROP = 192.0f; + + return IsJumpLegal( startPos, apex, endPos, MAX_JUMP_RISE, MAX_JUMP_DROP, MAX_JUMP_DISTANCE ); +} + +//----------------------------------------------------------------------------- +// Purpose: Returns a throw velocity from start to end position +// Input : +// Output : +//----------------------------------------------------------------------------- +Vector CAI_BaseNPC::CalcThrowVelocity(const Vector &startPos, const Vector &endPos, float fGravity, float fArcSize) +{ + // Get the height I have to throw to get to the target + float stepHeight = endPos.z - startPos.z; + float throwHeight = 0; + + // ----------------------------------------------------------------- + // Now calcluate the distance to a point halfway between our current + // and target position. (the apex of our throwing arc) + // ----------------------------------------------------------------- + Vector targetDir2D = endPos - startPos; + targetDir2D.z = 0; + + float distance = VectorNormalize(targetDir2D); + + + // If jumping up we want to throw a bit higher than the height diff + if (stepHeight > 0) + { + throwHeight = stepHeight + fArcSize; + } + else + { + throwHeight = fArcSize; + } + // Make sure that I at least catch some air + if (throwHeight < fArcSize) + { + throwHeight = fArcSize; + } + + + // ------------------------------------------------------------- + // calculate the vertical and horizontal launch velocities + // ------------------------------------------------------------- + float velVert = (float)sqrt(2.0f*fGravity*throwHeight); + + float divisor = velVert; + divisor += (float)sqrt((2.0f*(-fGravity)*(stepHeight-throwHeight))); + + float velHorz = (distance * fGravity)/divisor; + + // ----------------------------------------------------------- + // Make the horizontal throw vector and add vertical component + // ----------------------------------------------------------- + Vector throwVel = targetDir2D * velHorz; + throwVel.z = velVert; + + return throwVel; +} + +bool CAI_BaseNPC::ShouldMoveWait() +{ + return (m_flMoveWaitFinished > gpGlobals->curtime); +} + +float CAI_BaseNPC::GetStepDownMultiplier() const +{ + return m_pNavigator->GetStepDownMultiplier(); +} + + +//----------------------------------------------------------------------------- +// Purpose: execute any movement this sequence may have +// Output : +//----------------------------------------------------------------------------- +bool CAI_BaseNPC::AutoMovement( CBaseEntity *pTarget, AIMoveTrace_t *pTraceResult ) +{ + return AutoMovement( GetAnimTimeInterval(), pTarget, pTraceResult ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : flInterval - +// - +// *pTraceResult - +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CAI_BaseNPC::AutoMovement( float flInterval, CBaseEntity *pTarget, AIMoveTrace_t *pTraceResult ) +{ + bool ignored; + Vector newPos; + QAngle newAngles; + + if (flInterval <= 0.0) + return true; + + m_ScheduleState.bTaskRanAutomovement = true; + + if (GetIntervalMovement( flInterval, ignored, newPos, newAngles )) + { + // DevMsg( "%.2f : (%.1f) %.1f %.1f %.1f\n", gpGlobals->curtime, (newPos - GetLocalOrigin()).Length(), newPos.x, newPos.y, newAngles.y ); + + if ( m_hCine ) + { + m_hCine->ModifyScriptedAutoMovement( &newPos ); + } + + if (GetMoveType() == MOVETYPE_STEP) + { + if (!(GetFlags() & FL_FLY)) + { + if ( !pTarget ) + { + pTarget = GetNavTargetEntity(); + } + + return ( GetMotor()->MoveGroundStep( newPos, pTarget, newAngles.y, false, true, pTraceResult ) == AIM_SUCCESS ); + } + else + { + // FIXME: here's no direct interface to a fly motor, plus this needs to support a state where going through the world is okay. + // FIXME: add callbacks into the script system for validation + // FIXME: add function on scripts to force only legal movements + // FIXME: GetIntervalMovement deals in Local space, nor global. Currently now way to communicate that through these interfaces. + SetLocalOrigin( newPos ); + SetLocalAngles( newAngles ); + return true; + } + } + else if (GetMoveType() == MOVETYPE_FLY) + { + Vector dist = newPos - GetLocalOrigin(); + + VectorScale( dist, 1.0 / flInterval, dist ); + + SetLocalVelocity( dist ); + return true; + } + } + return false; +} + +//----------------------------------------------------------------------------- +// Purpose: return max 1/10 second rate of turning +// Input : +// Output : +//----------------------------------------------------------------------------- + +float CAI_BaseNPC::MaxYawSpeed( void ) +{ + return 45; +} + +//----------------------------------------------------------------------------- +// Returns the estimate in seconds before we reach our nav goal. +// -1 means we don't know / haven't calculated it yet. +//----------------------------------------------------------------------------- +float CAI_BaseNPC::GetTimeToNavGoal() +{ + float flDist = GetNavigator()->BuildAndGetPathDistToGoal(); + if ( flDist < 0 ) + { + return -1.0f; + } + + float flSpeed = GetIdealSpeed(); + + // FIXME: needs to consider stopping time! + if (flSpeed > 0 && flDist > 0) + { + return flDist / flSpeed; + } + return 0.0; +} + +//============================================================================= |