You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
275 lines
7.3 KiB
275 lines
7.3 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: Base combat character with no AI |
|
// |
|
// $Workfile: $ |
|
// $Date: $ |
|
// |
|
//----------------------------------------------------------------------------- |
|
// $Log: $ |
|
// |
|
// $NoKeywords: $ |
|
//=============================================================================// |
|
|
|
#include "cbase.h" |
|
#include "ai_hull.h" |
|
#include "ai_node.h" |
|
#include "ai_link.h" |
|
#include "ai_network.h" |
|
#include "ai_initutils.h" |
|
#include "bitstring.h" |
|
#include "ai_basenpc.h" |
|
#include "ai_navigator.h" |
|
#include "ai_moveprobe.h" |
|
#include "fmtstr.h" |
|
#include "game.h" |
|
#include "ai_networkmanager.h" |
|
|
|
// memdbgon must be the last include file in a .cpp file!!! |
|
#include "tier0/memdbgon.h" |
|
|
|
//----------------------------------------------------------------------------- |
|
|
|
CAI_Link *CAI_Node::GetLink( int destNodeId ) |
|
{ |
|
// Now make sure this node still has a link to the destID |
|
for ( int link = 0; link < NumLinks(); link++ ) |
|
{ |
|
// If we find the link the dynamic link is valid |
|
if ( m_Links[link]->DestNodeID(m_iID) == destNodeId ) |
|
{ |
|
return m_Links[link]; |
|
} |
|
} |
|
|
|
return NULL; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Add a link to this node |
|
// Input : |
|
// Output : |
|
//----------------------------------------------------------------------------- |
|
void CAI_Node::AddLink(CAI_Link *newLink) |
|
{ |
|
if ( NumLinks() == AI_MAX_NODE_LINKS ) |
|
{ |
|
DevMsg( "Node %d has too many links\n", m_iID ); |
|
return; |
|
} |
|
|
|
#ifdef _DEBUG |
|
for (int link=0;link<NumLinks();link++) |
|
{ |
|
if (m_Links[link] == newLink) |
|
{ |
|
AssertMsgOnce( 0, "Link added to node multiple times!" ); |
|
return; |
|
} |
|
} |
|
|
|
AssertMsg( newLink->m_iDestID == m_iID || newLink->m_iSrcID == m_iID, "Added link to node that doesn't reference the node" ); |
|
#endif |
|
|
|
m_Links.AddToTail( newLink ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Returns link if node has a link to node of the given nNodeID. |
|
// Otherwise returns NULL |
|
// Input : |
|
// Output : |
|
//----------------------------------------------------------------------------- |
|
CAI_Link* CAI_Node::HasLink(int nNodeID) |
|
{ |
|
for (int link=0;link<NumLinks();link++) |
|
{ |
|
// If node has link to myself, than add link to my list of links |
|
if (m_Links[link]->DestNodeID(m_iID) == nNodeID) |
|
{ |
|
return m_Links[link]; |
|
} |
|
} |
|
return NULL; |
|
} |
|
|
|
//------------------------------------------------------------------------------ |
|
// Purpose : Called before GetShuffeledLinks to change the order in which |
|
// links are returned |
|
// Input : |
|
// Output : |
|
//------------------------------------------------------------------------------ |
|
void CAI_Node::ShuffleLinks(void) |
|
{ |
|
m_iFirstShuffledLink++; |
|
if (m_iFirstShuffledLink >= NumLinks()) |
|
{ |
|
m_iFirstShuffledLink = 0; |
|
} |
|
} |
|
|
|
//------------------------------------------------------------------------------ |
|
// Purpose : Used to get links in different order each time. |
|
// Call ShuffleLinks() first |
|
// Input : |
|
// Output : |
|
//------------------------------------------------------------------------------ |
|
CAI_Link* CAI_Node::GetShuffeledLink(int nNum) |
|
{ |
|
int nLinkID = m_iFirstShuffledLink + nNum; |
|
if (nLinkID >= NumLinks()) |
|
{ |
|
nLinkID -= NumLinks(); |
|
} |
|
return m_Links[nLinkID]; |
|
} |
|
|
|
//---------------------------------------------------------------------------------- |
|
// Purpose: Returns z value of floor below given point (up to fMaxDrop inches below) |
|
// Input : |
|
// Output : |
|
//---------------------------------------------------------------------------------- |
|
float GetFloorZ(const Vector &origin, float fMaxDrop) |
|
{ |
|
// trace to the ground, then pop up 8 units and place node there to make it |
|
// easier for them to connect (think stairs, chairs, and bumps in the floor). |
|
// After the routing is done, push them back down. |
|
// |
|
trace_t tr; |
|
AI_TraceLine ( origin, |
|
origin - Vector ( 0, 0, fMaxDrop ), |
|
MASK_NPCSOLID_BRUSHONLY, |
|
NULL, |
|
COLLISION_GROUP_NONE, |
|
&tr ); |
|
|
|
// This trace is ONLY used if we hit an entity flagged with FL_WORLDBRUSH |
|
trace_t trEnt; |
|
AI_TraceLine ( origin, |
|
origin - Vector ( 0, 0, fMaxDrop ), |
|
MASK_NPCSOLID, |
|
NULL, |
|
COLLISION_GROUP_NONE, |
|
&trEnt ); |
|
|
|
|
|
// Did we hit something closer than the floor? |
|
if ( trEnt.fraction < tr.fraction ) |
|
{ |
|
// If it was a world brush entity, copy the node location |
|
if ( trEnt.m_pEnt ) |
|
{ |
|
CBaseEntity *e = trEnt.m_pEnt; |
|
if ( e && ( e->GetFlags() & FL_WORLDBRUSH ) ) |
|
{ |
|
tr.endpos = trEnt.endpos; |
|
} |
|
} |
|
} |
|
|
|
return tr.endpos.z; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Returns z value of floor below given point (up to 384 inches below) |
|
// Input : |
|
// Output : |
|
//----------------------------------------------------------------------------- |
|
float GetFloorZ(const Vector &origin) |
|
{ |
|
return GetFloorZ(origin, 384); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Returns distance of floor from the origin (up to 384 inches) |
|
// Input : |
|
// Output : |
|
//----------------------------------------------------------------------------- |
|
float GetFloorDistance(const Vector &origin) |
|
{ |
|
return (origin.z - GetFloorZ(origin)); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Climb nodes are centered over the climb surface, the must be |
|
// shifted away from the climb surface according to the hull size |
|
// of the NPC using the climb |
|
// Input : |
|
// Output : |
|
//----------------------------------------------------------------------------- |
|
Vector CAI_Node::GetPosition(int hull) |
|
{ |
|
if (m_eNodeType == NODE_CLIMB) |
|
{ |
|
// Shift by the length of the hull and some small fudge |
|
float shift = (0.5*NAI_Hull::Length(hull)) + (NODE_CLIMB_OFFSET); |
|
|
|
Vector offsetDir = Vector(cos(DEG2RAD(m_flYaw)),sin(DEG2RAD(m_flYaw)),0); |
|
|
|
Vector origin; |
|
if (m_eNodeInfo & bits_NODE_CLIMB_OFF_FORWARD) |
|
{ |
|
origin = m_vOrigin + (shift * offsetDir); |
|
} |
|
else if (m_eNodeInfo & bits_NODE_CLIMB_OFF_LEFT) |
|
{ |
|
Vector upDir(0,0,1); |
|
Vector leftDir; |
|
CrossProduct( offsetDir, upDir, leftDir); |
|
origin = m_vOrigin - (2 * shift * leftDir) - (shift * offsetDir); |
|
} |
|
else if (m_eNodeInfo & bits_NODE_CLIMB_OFF_RIGHT) |
|
{ |
|
Vector upDir(0,0,1); |
|
Vector leftDir; |
|
CrossProduct( offsetDir, upDir, leftDir); |
|
origin = m_vOrigin + (2 * shift * leftDir) - (shift * offsetDir); |
|
} |
|
else |
|
{ |
|
origin = m_vOrigin - (shift * offsetDir); |
|
} |
|
|
|
return Vector( origin.x, origin.y, origin.z + m_flVOffset[hull] ); |
|
} |
|
else if (m_eNodeType == NODE_GROUND) |
|
{ |
|
// this is the floor resting position of this hull, adjusted to account for mins.z |
|
return Vector( m_vOrigin.x, m_vOrigin.y, m_vOrigin.z + m_flVOffset[hull] ); |
|
} |
|
else |
|
{ |
|
return m_vOrigin; |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Constructor |
|
// Input : |
|
// Output : |
|
//----------------------------------------------------------------------------- |
|
CAI_Node::CAI_Node( int id, const Vector &origin, float yaw ) |
|
: m_Links( 0, 4 ) |
|
{ |
|
m_vOrigin = origin; |
|
m_iID = id; |
|
|
|
for (int i = 0; i < NUM_HULLS; i++) |
|
{ |
|
m_flVOffset[i] = 0.0; |
|
} |
|
|
|
m_eNodeType = NODE_GROUND; |
|
m_eNodeInfo = 0; |
|
|
|
m_iFirstShuffledLink = 0; |
|
|
|
m_pHint = NULL; |
|
m_flYaw = yaw; |
|
|
|
m_flNextUseTime = 0; |
|
|
|
m_zone = AI_NODE_ZONE_UNKNOWN; |
|
}; |
|
|
|
|