NSTalkMonster: pathfinding fixes that benefit following players around the maps. More failsafes.
This commit is contained in:
parent
7d9de3a2cc
commit
a623b1e301
5 changed files with 169 additions and 25 deletions
|
@ -14,8 +14,8 @@
|
||||||
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var float autocvar_ai_walkSpeed = 64;
|
var float autocvar_ai_walkSpeed = 150;
|
||||||
var float autocvar_ai_runSpeed = 364;
|
var float autocvar_ai_runSpeed = 320;
|
||||||
|
|
||||||
void
|
void
|
||||||
NSMonster::NSMonster(void)
|
NSMonster::NSMonster(void)
|
||||||
|
@ -97,6 +97,7 @@ NSMonster::NSMonster(void)
|
||||||
m_flRunSpeed = autocvar_ai_runSpeed;
|
m_flRunSpeed = autocvar_ai_runSpeed;
|
||||||
m_flLeapDamage = 0;
|
m_flLeapDamage = 0;
|
||||||
m_bLeapAttacked = false;
|
m_bLeapAttacked = false;
|
||||||
|
maxspeed = 1024;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -781,14 +782,19 @@ NSMonster::GetYawSpeed(void)
|
||||||
void
|
void
|
||||||
NSMonster::_LerpTurnToYaw(vector turnYaw)
|
NSMonster::_LerpTurnToYaw(vector turnYaw)
|
||||||
{
|
{
|
||||||
#if 1
|
#if 0
|
||||||
angles[1] = input_angles[1] = v_angle[1] = turnYaw[1];
|
angles[1] = input_angles[1] = v_angle[1] = turnYaw[1];
|
||||||
#else
|
#else
|
||||||
float turnSpeed = GetYawSpeed();
|
float turnSpeed = GetYawSpeed();
|
||||||
vector vecWishAngle = turnYaw;
|
vector vecWishAngle = turnYaw;
|
||||||
float yawDiff = anglesub(turnYaw[1], v_angle[1]);
|
float yawDiff = anglesub(turnYaw[1], v_angle[1]);
|
||||||
|
|
||||||
if (fabs(yawDiff) > 90) {
|
/* anything but small turns? halt the player */
|
||||||
|
if (fabs(yawDiff) > 5) {
|
||||||
|
input_movevalues = g_vec_null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fabs(yawDiff) > 45) {
|
||||||
velocity = g_vec_null;
|
velocity = g_vec_null;
|
||||||
input_movevalues = g_vec_null;
|
input_movevalues = g_vec_null;
|
||||||
|
|
||||||
|
@ -1238,13 +1244,13 @@ NSMonster::RouteEnded(void)
|
||||||
m_iSequenceState = SEQUENCESTATE_ENDING;
|
m_iSequenceState = SEQUENCESTATE_ENDING;
|
||||||
think = (m_iSequenceFlags & SSFL_NOSCRIPTMOVE) ? FreeState : FreeStateMoved;
|
think = (m_iSequenceFlags & SSFL_NOSCRIPTMOVE) ? FreeState : FreeStateMoved;
|
||||||
nextthink = time + duration;
|
nextthink = time + duration;
|
||||||
NSMonster_Log("^2%s::^3CheckRoute^7: %s overriding anim for %f seconds (modelindex %d, frame %d)", \
|
NSMonster_Log("^2%s::^3RouteEnded^7: %s overriding anim for %f seconds (modelindex %d, frame %d)", \
|
||||||
classname, this.targetname, duration, modelindex, m_flSequenceEnd);
|
classname, this.targetname, duration, modelindex, m_flSequenceEnd);
|
||||||
} else {
|
} else {
|
||||||
/* we still need to trigger targets */
|
/* we still need to trigger targets */
|
||||||
think = (m_iSequenceFlags & SSFL_NOSCRIPTMOVE) ? FreeState : FreeStateMoved;
|
think = (m_iSequenceFlags & SSFL_NOSCRIPTMOVE) ? FreeState : FreeStateMoved;
|
||||||
nextthink = time;
|
nextthink = time;
|
||||||
NSMonster_Log("^2%s::^3CheckRoute^7: %s has no anim, finished sequence", \
|
NSMonster_Log("^2%s::^3RouteEnded^7: %s has no anim, finished sequence", \
|
||||||
classname, this.targetname);
|
classname, this.targetname);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1252,6 +1258,7 @@ NSMonster::RouteEnded(void)
|
||||||
void
|
void
|
||||||
NSMonster::WalkRoute(void)
|
NSMonster::WalkRoute(void)
|
||||||
{
|
{
|
||||||
|
|
||||||
/* we're busy shooting at something, don't walk */
|
/* we're busy shooting at something, don't walk */
|
||||||
if (GetState() == MONSTER_AIMING && m_eEnemy) {
|
if (GetState() == MONSTER_AIMING && m_eEnemy) {
|
||||||
input_angles = vectoangles(m_eEnemy.origin - origin);
|
input_angles = vectoangles(m_eEnemy.origin - origin);
|
||||||
|
@ -1260,6 +1267,33 @@ NSMonster::WalkRoute(void)
|
||||||
input_angles = GetRouteDirection();
|
input_angles = GetRouteDirection();
|
||||||
input_angles[0] = input_angles[2] = 0;
|
input_angles[0] = input_angles[2] = 0;
|
||||||
input_movevalues = GetRouteMovevalues() * m_flSequenceSpeed;
|
input_movevalues = GetRouteMovevalues() * m_flSequenceSpeed;
|
||||||
|
|
||||||
|
/* is something in our way? */
|
||||||
|
makevectors(input_angles);
|
||||||
|
tracebox(origin, mins, maxs, origin + v_forward * 256, MOVE_NORMAL, this);
|
||||||
|
|
||||||
|
/* indeed it is */
|
||||||
|
if (trace_fraction < 1.0f) {
|
||||||
|
vector testOrg = origin + (v_right * 32);
|
||||||
|
testOrg[2] += mins[2] + 18.0f; /* test at feet level */
|
||||||
|
|
||||||
|
traceline(testOrg, testOrg + v_forward * 256, MOVE_NORMAL, this);
|
||||||
|
|
||||||
|
/* is space free to the right? */
|
||||||
|
if (trace_fraction == 1.0) {
|
||||||
|
input_movevalues[1] = m_flSequenceSpeed * 0.25f;
|
||||||
|
} else {
|
||||||
|
|
||||||
|
testOrg = origin - (v_right * 32);
|
||||||
|
testOrg[2] += mins[2] + 18.0f; /* test at feet level */
|
||||||
|
|
||||||
|
traceline(testOrg, testOrg + v_forward * 256, MOVE_NORMAL, this);
|
||||||
|
|
||||||
|
/* is space free to the left? */
|
||||||
|
if (trace_fraction == 1.0)
|
||||||
|
input_movevalues[1] = -m_flSequenceSpeed * 0.25f;
|
||||||
|
}
|
||||||
|
}
|
||||||
} else if (GetState() == MONSTER_CHASING && m_eEnemy) {
|
} else if (GetState() == MONSTER_CHASING && m_eEnemy) {
|
||||||
/* we've got 'em in our sights, just need to walk closer */
|
/* we've got 'em in our sights, just need to walk closer */
|
||||||
input_angles = vectoangles(m_eEnemy.origin - origin);
|
input_angles = vectoangles(m_eEnemy.origin - origin);
|
||||||
|
@ -1268,6 +1302,11 @@ NSMonster::WalkRoute(void)
|
||||||
} else
|
} else
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
/* don't move while turning. */
|
||||||
|
if (m_bTurning == true) {
|
||||||
|
input_movevalues = [0,0,0];
|
||||||
|
}
|
||||||
|
|
||||||
/* yaw interpolation */
|
/* yaw interpolation */
|
||||||
_LerpTurnToYaw(input_angles);
|
_LerpTurnToYaw(input_angles);
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,6 +44,10 @@ private:
|
||||||
vector m_vecTurnAngle;
|
vector m_vecTurnAngle;
|
||||||
string m_pathTarget;
|
string m_pathTarget;
|
||||||
NSEntity m_pathEntity;
|
NSEntity m_pathEntity;
|
||||||
|
float _m_flRouteGiveUp;
|
||||||
|
vector _m_vecRoutePrev;
|
||||||
|
vector m_vecRouteEntity;
|
||||||
|
entity m_eFollowing;
|
||||||
|
|
||||||
/* These are defined in side defs\*.def, ammo_types and ammo_names */
|
/* These are defined in side defs\*.def, ammo_types and ammo_names */
|
||||||
int m_iAmmoTypes[MAX_AMMO_TYPES];
|
int m_iAmmoTypes[MAX_AMMO_TYPES];
|
||||||
|
|
|
@ -24,6 +24,8 @@ NSNavAI::NSNavAI(void)
|
||||||
m_vecLastNode = [0,0,0];
|
m_vecLastNode = [0,0,0];
|
||||||
m_vecTurnAngle = [0,0,0];
|
m_vecTurnAngle = [0,0,0];
|
||||||
|
|
||||||
|
_m_flRouteGiveUp = 0.0f;
|
||||||
|
|
||||||
for (int i = 0; i < MAX_AMMO_TYPES; i++)
|
for (int i = 0; i < MAX_AMMO_TYPES; i++)
|
||||||
m_iAmmoTypes[i] = 0;
|
m_iAmmoTypes[i] = 0;
|
||||||
#endif
|
#endif
|
||||||
|
@ -108,6 +110,7 @@ void
|
||||||
NSNavAI::CheckRoute(void)
|
NSNavAI::CheckRoute(void)
|
||||||
{
|
{
|
||||||
float flDist;
|
float flDist;
|
||||||
|
float flNodeRadius;
|
||||||
vector evenpos;
|
vector evenpos;
|
||||||
|
|
||||||
if (m_pathTarget) {
|
if (m_pathTarget) {
|
||||||
|
@ -118,18 +121,41 @@ NSNavAI::CheckRoute(void)
|
||||||
if (!m_iNodes)
|
if (!m_iNodes)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (_m_flRouteGiveUp < time) {
|
||||||
|
/* 50 units in 2 seconds is not good. */
|
||||||
|
if (vlen(_m_vecRoutePrev - origin) < 50.0f) {
|
||||||
|
/* HACK: for followers */
|
||||||
|
if (m_eFollowing) {
|
||||||
|
RouteToPosition(m_eFollowing.origin);
|
||||||
|
NSNavAI_Log("^2%s::^3CheckRoute^7: " \
|
||||||
|
"Giving up current route to follower, re-calculating", classname);
|
||||||
|
} else {
|
||||||
|
RouteToPosition(m_vecLastNode);
|
||||||
|
NSNavAI_Log("^2%s::^3CheckRoute^7: " \
|
||||||
|
"Giving up current route, re-calculating", classname);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_m_flRouteGiveUp = time + 2.0f;
|
||||||
|
_m_vecRoutePrev = origin;
|
||||||
|
}
|
||||||
|
|
||||||
/* level out position/node stuff */
|
/* level out position/node stuff */
|
||||||
if (m_iCurNode < 0) {
|
if (m_iCurNode < 0) {
|
||||||
evenpos = m_vecLastNode;
|
evenpos = m_vecLastNode;
|
||||||
evenpos[2] = origin[2];
|
evenpos[2] = origin[2];
|
||||||
|
flNodeRadius = 8.0f;
|
||||||
} else {
|
} else {
|
||||||
evenpos = m_pRoute[m_iCurNode].dest;
|
evenpos = m_pRoute[m_iCurNode].dest;
|
||||||
evenpos[2] = origin[2];
|
evenpos[2] = origin[2];
|
||||||
|
flNodeRadius = m_pRoute[m_iCurNode].radius;
|
||||||
|
|
||||||
|
if (flNodeRadius <= 0.0)
|
||||||
|
flNodeRadius = 8.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
flDist = floor(vlen(evenpos - origin));
|
flDist = floor(vlen(evenpos - origin));
|
||||||
|
|
||||||
if (flDist < 8) {
|
if (flDist < flNodeRadius) {
|
||||||
NSNavAI_Log("^2%s::^3CheckRoute^7: " \
|
NSNavAI_Log("^2%s::^3CheckRoute^7: " \
|
||||||
"%s reached node", classname, targetname);
|
"%s reached node", classname, targetname);
|
||||||
m_iCurNode--;
|
m_iCurNode--;
|
||||||
|
@ -149,12 +175,14 @@ NSNavAI::CheckRoute(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 1
|
||||||
/* check if we can reach the node after the current one */
|
/* check if we can reach the node after the current one */
|
||||||
if (m_iCurNode > 0 && m_iNodes > 3) { /* HACK: only bother when we have more than 3 nodes in the path... this works around an issue in c1a0d I'm unsure about */
|
if (m_iCurNode > 0 && m_iNodes > 3) { /* HACK: only bother when we have more than 3 nodes in the path... this works around an issue in c1a0d I'm unsure about */
|
||||||
int iNextNode = (m_iCurNode - 1);
|
int iNextNode = (m_iCurNode - 1);
|
||||||
vector vecNextNode = m_pRoute[iNextNode].dest;
|
vector vecNextNode = m_pRoute[iNextNode].dest;
|
||||||
|
|
||||||
tracebox(origin, mins, maxs, vecNextNode, MOVE_NORMAL, this);
|
other = world;
|
||||||
|
tracebox(origin, mins, maxs, vecNextNode, MOVE_OTHERONLY, this);
|
||||||
|
|
||||||
/* it's accessible */
|
/* it's accessible */
|
||||||
if (!trace_startsolid && trace_fraction == 1.0f) {
|
if (!trace_startsolid && trace_fraction == 1.0f) {
|
||||||
|
@ -162,8 +190,10 @@ NSNavAI::CheckRoute(void)
|
||||||
m_iCurNode = iNextNode;
|
m_iCurNode = iNextNode;
|
||||||
NSNavAI_Log("^2%s::^3CheckRoute^7: skipping to next node %i at '%v'", \
|
NSNavAI_Log("^2%s::^3CheckRoute^7: skipping to next node %i at '%v'", \
|
||||||
classname, iNextNode, vecNextNode);
|
classname, iNextNode, vecNextNode);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* reached the end of the line */
|
/* reached the end of the line */
|
||||||
if (m_iCurNode < -1) {
|
if (m_iCurNode < -1) {
|
||||||
|
|
|
@ -67,6 +67,8 @@ They also can communicate with other NSTalkMonster based entities.
|
||||||
- "talk_stop_follow" : SentenceDef to play for when they're being asked to unfollow someone.
|
- "talk_stop_follow" : SentenceDef to play for when they're being asked to unfollow someone.
|
||||||
- "talk_deny_follow" : SentenceDef to play for when they're denying the follow request.
|
- "talk_deny_follow" : SentenceDef to play for when they're denying the follow request.
|
||||||
- "follow_on_use" : Can be either 0 or 1, will decide if they can follow someone.
|
- "follow_on_use" : Can be either 0 or 1, will decide if they can follow someone.
|
||||||
|
- "follow_dist" : Distance between the it and the player its following.
|
||||||
|
- "follow_maxdist" : Maximum distance between it and the player before giving up following them.
|
||||||
|
|
||||||
For more keys, see NSMonster.
|
For more keys, see NSMonster.
|
||||||
*/
|
*/
|
||||||
|
@ -102,6 +104,7 @@ public:
|
||||||
virtual float SendEntity(entity,float);
|
virtual float SendEntity(entity,float);
|
||||||
virtual void Save(float);
|
virtual void Save(float);
|
||||||
virtual void Restore(string,string);
|
virtual void Restore(string,string);
|
||||||
|
virtual void Touch(entity);
|
||||||
|
|
||||||
/*virtual void(void) TalkAnswer;
|
/*virtual void(void) TalkAnswer;
|
||||||
virtual void(void) TalkAsk;
|
virtual void(void) TalkAsk;
|
||||||
|
@ -158,7 +161,6 @@ private:
|
||||||
float m_flNextSentence;
|
float m_flNextSentence;
|
||||||
int m_iFlags;
|
int m_iFlags;
|
||||||
|
|
||||||
entity m_eFollowing;
|
|
||||||
entity m_eFollowingChain;
|
entity m_eFollowingChain;
|
||||||
vector m_vecLastUserPos;
|
vector m_vecLastUserPos;
|
||||||
float m_flChangePath;
|
float m_flChangePath;
|
||||||
|
@ -167,6 +169,10 @@ private:
|
||||||
float m_flFollowSpeed;
|
float m_flFollowSpeed;
|
||||||
bool m_bFollowOnUse;
|
bool m_bFollowOnUse;
|
||||||
|
|
||||||
|
float m_flFollowDistance;
|
||||||
|
float m_flMaxFollowDistance;
|
||||||
|
bool m_bFollowGrouping;
|
||||||
|
|
||||||
/* sentences identifiers */
|
/* sentences identifiers */
|
||||||
string m_talkAnswer; /* random answer to whenever a question is asked */
|
string m_talkAnswer; /* random answer to whenever a question is asked */
|
||||||
string m_talkAsk; /* asks a random generic question */
|
string m_talkAsk; /* asks a random generic question */
|
||||||
|
|
|
@ -51,6 +51,9 @@ NSTalkMonster::NSTalkMonster(void)
|
||||||
m_talkStopFollow = __NULL__;
|
m_talkStopFollow = __NULL__;
|
||||||
m_talkDenyFollow = __NULL__;
|
m_talkDenyFollow = __NULL__;
|
||||||
m_bFollowOnUse = false;
|
m_bFollowOnUse = false;
|
||||||
|
m_flFollowDistance = 128.0f;
|
||||||
|
m_flMaxFollowDistance = 2048.0f;
|
||||||
|
m_bFollowGrouping = false;
|
||||||
#else
|
#else
|
||||||
m_flSentenceTime = 0.0f;
|
m_flSentenceTime = 0.0f;
|
||||||
m_pSentenceQue = __NULL__;
|
m_pSentenceQue = __NULL__;
|
||||||
|
@ -102,6 +105,8 @@ NSTalkMonster::Save(float handle)
|
||||||
SaveFloat(handle, "m_flFollowSpeedChanged", m_flFollowSpeedChanged);
|
SaveFloat(handle, "m_flFollowSpeedChanged", m_flFollowSpeedChanged);
|
||||||
SaveFloat(handle, "m_flFollowSpeed", m_flFollowSpeed);
|
SaveFloat(handle, "m_flFollowSpeed", m_flFollowSpeed);
|
||||||
SaveBool(handle, "m_bFollowOnUse", m_bFollowOnUse);
|
SaveBool(handle, "m_bFollowOnUse", m_bFollowOnUse);
|
||||||
|
SaveFloat(handle, "m_flFollowDistance", m_flFollowDistance);
|
||||||
|
SaveFloat(handle, "m_flMaxFollowDistance", m_flMaxFollowDistance);
|
||||||
|
|
||||||
SaveString(handle, "m_talkAnswer", m_talkAnswer);
|
SaveString(handle, "m_talkAnswer", m_talkAnswer);
|
||||||
SaveString(handle, "m_talkAsk", m_talkAsk);
|
SaveString(handle, "m_talkAsk", m_talkAsk);
|
||||||
|
@ -164,6 +169,12 @@ NSTalkMonster::Restore(string strKey, string strValue)
|
||||||
case "m_bFollowOnUse":
|
case "m_bFollowOnUse":
|
||||||
m_bFollowOnUse = ReadBool(strValue);
|
m_bFollowOnUse = ReadBool(strValue);
|
||||||
break;
|
break;
|
||||||
|
case "m_flFollowDistance":
|
||||||
|
m_flFollowDistance = ReadFloat(strValue);
|
||||||
|
break;
|
||||||
|
case "m_flMaxFollowDistance":
|
||||||
|
m_flMaxFollowDistance = ReadFloat(strValue);
|
||||||
|
break;
|
||||||
case "m_talkAnswer":
|
case "m_talkAnswer":
|
||||||
m_talkAnswer = ReadString(strValue);
|
m_talkAnswer = ReadString(strValue);
|
||||||
break;
|
break;
|
||||||
|
@ -505,6 +516,22 @@ NSTalkMonster::TalkDenyFollow(void)
|
||||||
m_flNextSentence = time + 10.0;
|
m_flNextSentence = time + 10.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
NSTalkMonster::Touch(entity eToucher)
|
||||||
|
{
|
||||||
|
if (eToucher == m_eFollowing) {
|
||||||
|
makevectors(eToucher.angles);
|
||||||
|
velocity = v_forward * 250.0f;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ugly hack */
|
||||||
|
if (eToucher.classname == "func_door_rotating") {
|
||||||
|
owner = eToucher;
|
||||||
|
}
|
||||||
|
|
||||||
|
super::Touch(eToucher);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
NSTalkMonster::FollowPlayer(void)
|
NSTalkMonster::FollowPlayer(void)
|
||||||
|
@ -525,41 +552,71 @@ NSTalkMonster::FollowPlayer(void)
|
||||||
flPlayerDist = vlen(vecParent - origin);
|
flPlayerDist = vlen(vecParent - origin);
|
||||||
|
|
||||||
/* Give up after 1024 units */
|
/* Give up after 1024 units */
|
||||||
if (flPlayerDist > 1024) {
|
if (flPlayerDist > m_flMaxFollowDistance) {
|
||||||
m_eFollowing = world;
|
m_eFollowing = world;
|
||||||
} else if (flPlayerDist > 128) {
|
NSMonster_Log("Maximum follow distance reached. Will stop following.");
|
||||||
|
} else if (flPlayerDist >= m_flFollowDistance) {
|
||||||
/* we only allow speed changes every second, avoid jitter */
|
/* we only allow speed changes every second, avoid jitter */
|
||||||
if (m_flFollowSpeedChanged < time) {
|
if (m_flFollowSpeedChanged < time) {
|
||||||
float flNextSpeed = GetChaseSpeed();
|
float flNextSpeed = GetChaseSpeed();
|
||||||
|
|
||||||
/* if we're close enough, we ought to walk */
|
/* if we're close enough, we ought to walk */
|
||||||
if (flPlayerDist < 256)
|
if (flPlayerDist < (m_flFollowDistance * 1.5f))
|
||||||
flNextSpeed = GetWalkSpeed();
|
flNextSpeed = GetWalkSpeed();
|
||||||
|
|
||||||
/* only update the timer when speed changed */
|
/* only update the timer when speed changed */
|
||||||
if (flNextSpeed != m_flFollowSpeed) {
|
if (flNextSpeed != m_flFollowSpeed) {
|
||||||
m_flFollowSpeed = flNextSpeed;
|
m_flFollowSpeed = flNextSpeed;
|
||||||
m_flFollowSpeedChanged = time + 1.0f;
|
m_flFollowSpeedChanged = time + 5.0f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (DistanceFromYaw(vecParent) > 0.9f)
|
if (DistanceFromYaw(vecParent) > 0.9f)
|
||||||
input_movevalues[0] = m_flFollowSpeed;
|
input_movevalues[0] = m_flFollowSpeed;
|
||||||
|
|
||||||
other = world;
|
/* when we're in a chain... can we see the user any more? */
|
||||||
traceline(origin, m_eFollowingChain.origin, MOVE_OTHERONLY, this);
|
if (m_eFollowingChain != m_eFollowing) {
|
||||||
|
traceline(GetOrigin(), m_eFollowing.origin, MOVE_NORMAL, this);
|
||||||
|
|
||||||
|
/* the answer is no. */
|
||||||
|
if (trace_fraction < 1.0 || trace_ent != m_eFollowing) {
|
||||||
|
/* go straight to our user */
|
||||||
|
NSEntity zamn = (NSEntity)m_eFollowing;
|
||||||
|
vector endPos = zamn.GetNearbySpot();
|
||||||
|
|
||||||
|
if (endPos != g_vec_null) {
|
||||||
|
RouteToPosition(endPos);
|
||||||
|
m_flSequenceSpeed = GetChaseSpeed();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
traceline(origin, m_eFollowingChain.origin, MOVE_NORMAL, this);
|
||||||
|
|
||||||
/* Tracing failed, there's world geometry in the way */
|
/* Tracing failed, there's world geometry in the way */
|
||||||
if (trace_fraction < 1.0f) {
|
if (trace_fraction < 1.0f && trace_ent != m_eFollowingChain) {
|
||||||
input_angles = vectoangles(m_vecLastUserPos - origin);
|
/* are they still generally accessible? */
|
||||||
input_angles[0] = 0;
|
traceline(m_vecLastUserPos, vecParent, MOVE_NORMAL, this);
|
||||||
input_angles[1] = Math_FixDelta(input_angles[1]);
|
|
||||||
input_angles[2] = 0;
|
if (trace_fraction < 1.0f && trace_ent != m_eFollowing) {
|
||||||
_LerpTurnToYaw(input_angles);
|
RouteToPosition(m_eFollowing.origin); /* go directly to the source */
|
||||||
|
m_flSequenceSpeed = GetChaseSpeed();
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
input_angles = vectoangles(m_vecLastUserPos - origin);
|
||||||
|
input_angles[0] = 0;
|
||||||
|
input_angles[1] = Math_FixDelta(input_angles[1]);
|
||||||
|
input_angles[2] = 0;
|
||||||
|
_LerpTurnToYaw(input_angles);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
m_vecLastUserPos = m_eFollowingChain.origin;
|
m_vecLastUserPos = vecParent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_bFollowGrouping == false)
|
||||||
|
return;
|
||||||
|
|
||||||
/* Trace again to see if another hostage is in our path and if so
|
/* Trace again to see if another hostage is in our path and if so
|
||||||
* follow them instead, this makes pathing easier */
|
* follow them instead, this makes pathing easier */
|
||||||
traceline(origin, /*mins, maxs,*/ m_vecLastUserPos, FALSE, this);
|
traceline(origin, /*mins, maxs,*/ m_vecLastUserPos, FALSE, this);
|
||||||
|
@ -578,8 +635,7 @@ void
|
||||||
NSTalkMonster::PanicFrame(void)
|
NSTalkMonster::PanicFrame(void)
|
||||||
{
|
{
|
||||||
m_iFlags |= MONSTER_METPLAYER;
|
m_iFlags |= MONSTER_METPLAYER;
|
||||||
maxspeed = 240;
|
input_movevalues = [240, 0, 0];
|
||||||
input_movevalues = [maxspeed, 0, 0];
|
|
||||||
|
|
||||||
if (m_flTraceTime < time) {
|
if (m_flTraceTime < time) {
|
||||||
traceline(origin, origin + (v_forward * 64), FALSE, this);
|
traceline(origin, origin + (v_forward * 64), FALSE, this);
|
||||||
|
@ -625,7 +681,7 @@ NSTalkMonster::RunAI(void)
|
||||||
TalkPlayerGreet();
|
TalkPlayerGreet();
|
||||||
FollowChain();
|
FollowChain();
|
||||||
|
|
||||||
if (m_eFollowing != world) {
|
if (m_eFollowing != world && m_iNodes <= 0) {
|
||||||
m_eLookAt = m_eFollowing;
|
m_eLookAt = m_eFollowing;
|
||||||
FollowPlayer();
|
FollowPlayer();
|
||||||
} else if (m_iFlags & MONSTER_FEAR) {
|
} else if (m_iFlags & MONSTER_FEAR) {
|
||||||
|
@ -644,6 +700,7 @@ NSTalkMonster::Respawn(void)
|
||||||
{
|
{
|
||||||
super::Respawn();
|
super::Respawn();
|
||||||
|
|
||||||
|
RouteClear();
|
||||||
m_eFollowing = world;
|
m_eFollowing = world;
|
||||||
m_eFollowingChain = world;
|
m_eFollowingChain = world;
|
||||||
PlayerUse = OnPlayerUse;
|
PlayerUse = OnPlayerUse;
|
||||||
|
@ -677,6 +734,7 @@ NSTalkMonster::OnPlayerUse(void)
|
||||||
} else {
|
} else {
|
||||||
TalkUnfollow();
|
TalkUnfollow();
|
||||||
m_eFollowing = world;
|
m_eFollowing = world;
|
||||||
|
RouteClear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -761,6 +819,13 @@ NSTalkMonster::SpawnKey(string strKey, string strValue)
|
||||||
case "follow_on_use":
|
case "follow_on_use":
|
||||||
m_bFollowOnUse = ReadBool(strValue);
|
m_bFollowOnUse = ReadBool(strValue);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case "follow_dist":
|
||||||
|
m_flFollowDistance = ReadFloat(strValue);
|
||||||
|
break;
|
||||||
|
case "follow_maxdist":
|
||||||
|
m_flMaxFollowDistance = ReadFloat(strValue);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
super::SpawnKey(strKey, strValue);
|
super::SpawnKey(strKey, strValue);
|
||||||
break;
|
break;
|
||||||
|
|
Loading…
Reference in a new issue