From bd7cb4478474a96c3837d0f07d1e782294f35cd8 Mon Sep 17 00:00:00 2001 From: Marco Cawthorne Date: Tue, 30 May 2023 12:06:16 -0700 Subject: [PATCH] AI: add ai_debugNav, and ai_debugLogic cvars. Add cooldown timer for targets --- src/shared/NSMonster.h | 14 ++++- src/shared/NSMonster.qc | 104 +++++++++++++++++++++++++------ src/shared/NSNavAI.h | 9 +++ src/shared/NSNavAI.qc | 12 ++-- src/shared/NSSurfacePropEntity.h | 5 ++ src/shared/NSTalkMonster.qc | 14 +++-- 6 files changed, 125 insertions(+), 33 deletions(-) diff --git a/src/shared/NSMonster.h b/src/shared/NSMonster.h index cfc9f2da..149cb9c9 100644 --- a/src/shared/NSMonster.h +++ b/src/shared/NSMonster.h @@ -14,6 +14,15 @@ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +var bool autocvar_ai_debugLogic = false; +void +_NSMonster_Log(string msg) +{ + if (autocvar_ai_debugLogic == true) + print(sprintf("%f %s\n", time, msg)); +} +#define NSMonster_Log(...) _NSMonster_Log(sprintf(__VA_ARGS__)) + /** Bitfield enumeration for NSMonster its SendFlags field. @@ -32,7 +41,7 @@ typedef enumflags MONFL_CHANGED_FLAGS, MONFL_CHANGED_SOLID, MONFL_CHANGED_FRAME, - MONFL_CHANGED_SKIN, + MONFL_CHANGED_SKINHEALTH, MONFL_CHANGED_MOVETYPE, MONFL_CHANGED_EFFECTS, MONFL_CHANGED_BODY, @@ -261,6 +270,9 @@ private: /* animation cycles */ float m_flAnimTime; + /* timer for keeping track of the target */ + float m_flTrackingTime; + PREDICTED_VECTOR_N(view_ofs) nonvirtual void _LerpTurnToEnemy(float); diff --git a/src/shared/NSMonster.qc b/src/shared/NSMonster.qc index 4f030450..67c3882f 100644 --- a/src/shared/NSMonster.qc +++ b/src/shared/NSMonster.qc @@ -23,6 +23,33 @@ NSMonster::NSMonster(void) remove(this); return; } + + m_ssLast = __NULL__; + oldnet_velocity = g_vec_null; + m_flPitch = 1.0f; + m_iFlags = 0i; + base_mins = g_vec_null; + base_maxs = g_vec_null; + base_health = 100; + m_strRouteEnded = __NULL__; + m_iSequenceRemove = 0i; + m_iSequenceState = 0i; + m_flSequenceEnd = 0.0f; + m_flSequenceSpeed = 0.0f; + m_vecSequenceAngle = g_vec_null; + m_iSequenceFlags = 0i; + m_iMoveState = 0i; + m_iTriggerCondition = 0i; + m_strTriggerTarget = __NULL__; + m_flBaseTime = 0.0f; + m_eEnemy = __NULL__; + m_flAttackThink = 0.0f; + m_iMState = 0i; + m_iOldMState = 0i; + m_vecLKPos = g_vec_null; + m_flSeeTime = 0.0f; + m_flAnimTime = 0.0f; + m_flTrackingTime = 0.0f; #endif } @@ -266,7 +293,7 @@ NSMonster::AlertNearby(void) if (vlen(origin - w.origin) > 512) continue; - //NSLog("Alert! %s get %s", w.classname, m_eEnemy.classname); + //NSMonster_Log("Alert! %s get %s", w.classname, m_eEnemy.classname); NSMonster f = (NSMonster)w; /* we shouldn't override this when they already got a target */ @@ -302,14 +329,41 @@ NSMonster::IsValidEnemy(entity enny) return TRUE; } +static bool +NSMonster_TraceAgainsTarget(NSMonster monster, NSEntity target) +{ + traceline(monster.GetEyePos(), target.GetOrigin(), MOVE_NORMAL, monster); + + /* we have line of sight with the player */ + if (trace_fraction == 1.0f || trace_ent == target) { + return true; + } + + return false; +} + void NSMonster::SeeThink(void) { if (m_flAttackThink < time) if (m_eEnemy) { /* check if we should invalidate current enemy */ - if (IsValidEnemy(m_eEnemy)) - return; + if (IsValidEnemy(m_eEnemy)) { + /* only update 1/4th of a second */ + if (m_flSeeTime > time) + return; + + m_flSeeTime = time + 0.25f; + + /* see if we can trace our target, if yes, update our timestamp */ + if (NSMonster_TraceAgainsTarget(this, (NSEntity) m_eEnemy) == true) { + m_flTrackingTime = time; + } + + /* if we haven't gotten a trace in 5 seconds, give up. */ + if ((m_flTrackingTime + 5.0) > time) + return; + } /* enemy is not valid anymore, reset it, clear route and search for new enemy */ RouteClear(); @@ -350,15 +404,13 @@ NSMonster::SeeThink(void) if (flDot < SeeFOV()/180) continue; - traceline(GetEyePos(), w.origin, MOVE_EVERYTHING, this); - /* we have line of sight with the player */ - if (trace_fraction == 1.0f || trace_ent == w) { + if (NSMonster_TraceAgainsTarget(this, (NSEntity)w) == true) { if (m_eEnemy != w) { m_eEnemy = w; + m_flTrackingTime = time; AlertNearby(); } - return; } } @@ -386,8 +438,11 @@ NSMonster::GetRunSpeed(void) void NSMonster::_LerpTurnToEnemy(float flSpeed) { + /* only continue if we're in one of the three states. */ if (GetState() != MONSTER_AIMING) - return; + if (GetState() != MONSTER_CHASING) + if (GetState() != MONSTER_FOLLOWING) + return; if (!m_eEnemy) return; @@ -451,7 +506,7 @@ NSMonster::AttackThink(void) if (GetState() == MONSTER_AIMING) { int m; - _LerpTurnToEnemy(1000); + _LerpTurnToEnemy(30); if (MeleeCondition() == TRUE) m = AttackMelee(); @@ -482,14 +537,14 @@ NSMonster::AttackRanged(void) void NSMonster::AttackDraw(void) { - NSLog("^1%s::AttackDraw: Not defined!", classname); + NSMonster_Log("^1%s::AttackDraw: Not defined!", classname); m_flAttackThink = time + 0.5f; } void NSMonster::AttackHolster(void) { - NSLog("^1%s::AttackHolster: Not defined!", classname); + NSMonster_Log("^1%s::AttackHolster: Not defined!", classname); m_flAttackThink = time + 0.5f; } @@ -526,7 +581,7 @@ NSMonster::FreeState(void) if (m_iSequenceRemove) { Hide(); } - NSLog("^2%s::^3FreeState^7: (%i, %S)", classname, m_iSequenceRemove, to_trigger); + NSMonster_Log("^2%s::^3FreeState^7: (%i, %S)", classname, m_iSequenceRemove, to_trigger); } void @@ -534,7 +589,7 @@ NSMonster::FreeStateMoved(void) { vector new_origin; new_origin = gettaginfo(this, 1); - NSLog("^2%s::^3FreeStateMoved^7: moved to %v", classname, new_origin); + NSMonster_Log("^2%s::^3FreeStateMoved^7: moved to %v", classname, new_origin); SetOrigin(new_origin); DropToFloor(); FreeState(); @@ -554,13 +609,13 @@ NSMonster::RouteEnded(void) m_iSequenceState = SEQUENCESTATE_ENDING; think = (m_iSequenceFlags & SSFL_NOSCRIPTMOVE) ? FreeState : FreeStateMoved; nextthink = time + duration; - NSLog("^2%s::^3CheckRoute^7: %s overriding anim for %f seconds (modelindex %d, frame %d)", \ + NSMonster_Log("^2%s::^3CheckRoute^7: %s overriding anim for %f seconds (modelindex %d, frame %d)", \ classname, this.targetname, duration, modelindex, m_flSequenceEnd); } else { /* we still need to trigger targets */ think = (m_iSequenceFlags & SSFL_NOSCRIPTMOVE) ? FreeState : FreeStateMoved; nextthink = time; - NSLog("^2%s::^3CheckRoute^7: %s has no anim, finished sequence", \ + NSMonster_Log("^2%s::^3CheckRoute^7: %s has no anim, finished sequence", \ classname, this.targetname); } } @@ -674,7 +729,7 @@ NSMonster::IsAlive(void) void NSMonster::StateChanged(monsterState_t oldState, monsterState_t newState) { - NSLog("^2%s::^3StateChanged^7: state changed from %d to %d", \ + NSMonster_Log("^2%s::^3StateChanged^7: state changed from %d to %d", \ classname, oldState, newState); } @@ -823,7 +878,10 @@ NSMonster::Pain(void) m_eEnemy = g_dmg_eAttacker; /* an alert monster will take a while to calm back down */ - SetState(MONSTER_ALERT); + if (GetState() != MONSTER_ALERT) + if (GetState() != MONSTER_FOLLOWING) + if (GetState() != MONSTER_CHASING) + SetState(MONSTER_ALERT); /* alert all nearby friendlies */ AlertNearby(); @@ -937,7 +995,8 @@ NSMonster::EvaluateEntity(void) EVALUATE_VECTOR(maxs, 1, MONFL_CHANGED_SIZE) EVALUATE_VECTOR(maxs, 2, MONFL_CHANGED_SIZE) EVALUATE_FIELD(frame, MONFL_CHANGED_FRAME) - EVALUATE_FIELD(skin, MONFL_CHANGED_SKIN) + EVALUATE_FIELD(skin, MONFL_CHANGED_SKINHEALTH) + EVALUATE_FIELD(health, MONFL_CHANGED_SKINHEALTH) EVALUATE_FIELD(effects, MONFL_CHANGED_EFFECTS) EVALUATE_FIELD(m_iBody, MONFL_CHANGED_BODY) EVALUATE_FIELD(scale, MONFL_CHANGED_SCALE) @@ -985,7 +1044,8 @@ NSMonster::SendEntity(entity ePEnt, float flChanged) SENDENTITY_COORD(maxs[1], MONFL_CHANGED_SIZE) SENDENTITY_COORD(maxs[2], MONFL_CHANGED_SIZE) SENDENTITY_BYTE(frame, MONFL_CHANGED_FRAME) - SENDENTITY_FLOAT(skin, MONFL_CHANGED_SKIN) + SENDENTITY_FLOAT(skin, MONFL_CHANGED_SKINHEALTH) + SENDENTITY_FLOAT(health, MONFL_CHANGED_SKINHEALTH) SENDENTITY_FLOAT(effects, MONFL_CHANGED_EFFECTS) SENDENTITY_BYTE(m_iBody, MONFL_CHANGED_BODY) SENDENTITY_FLOAT(scale, MONFL_CHANGED_SCALE) @@ -1060,7 +1120,8 @@ NSMonster::ReceiveEntity(float flNew, float flChanged) READENTITY_COORD(maxs[1], MONFL_CHANGED_SIZE) READENTITY_COORD(maxs[2], MONFL_CHANGED_SIZE) READENTITY_BYTE(frame, MONFL_CHANGED_FRAME) - READENTITY_FLOAT(skin, MONFL_CHANGED_SKIN) + READENTITY_FLOAT(skin, MONFL_CHANGED_SKINHEALTH) + READENTITY_FLOAT(health, MONFL_CHANGED_SKINHEALTH) READENTITY_FLOAT(effects, MONFL_CHANGED_EFFECTS) READENTITY_BYTE(m_iBody, MONFL_CHANGED_BODY) READENTITY_FLOAT(scale, MONFL_CHANGED_SCALE) @@ -1094,6 +1155,9 @@ NSMonster::_RenderDebugViewCone(void) float flDot; vector testOrg; + if (health <= 0 || solid == SOLID_CORPSE) + return; + if (autocvar(r_showViewCone, 0) == 0) return; diff --git a/src/shared/NSNavAI.h b/src/shared/NSNavAI.h index 1d9aeed6..aa0fccd1 100644 --- a/src/shared/NSNavAI.h +++ b/src/shared/NSNavAI.h @@ -14,6 +14,15 @@ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +var bool autocvar_ai_debugNav = false; +void +_NSNavAI_Log(string msg) +{ + if (autocvar_ai_debugNav == true) + print(sprintf("%f %s\n", time, msg)); +} +#define NSNavAI_Log(...) _NSNavAI_Log(sprintf(__VA_ARGS__)) + #ifndef MAX_AMMO_TYPES #define MAX_AMMO_TYPES 16 #endif diff --git a/src/shared/NSNavAI.qc b/src/shared/NSNavAI.qc index 2a079995..72137e0e 100644 --- a/src/shared/NSNavAI.qc +++ b/src/shared/NSNavAI.qc @@ -107,7 +107,7 @@ NSNavAI::CheckRoute(void) flDist = floor(vlen(evenpos - origin)); if (flDist < 8) { - NSLog("^2%s::^3CheckRoute^7: " \ + NSNavAI_Log("^2%s::^3CheckRoute^7: " \ "%s reached node", classname, targetname); m_iCurNode--; velocity = [0,0,0]; /* clamp friction */ @@ -119,7 +119,7 @@ NSNavAI::CheckRoute(void) /* can we walk directly to our target destination? */ if (trace_fraction == 1.0) { - NSLog("^2%s::^3CheckRoute^7: Walking directly to last node at '%v'", \ + NSNavAI_Log("^2%s::^3CheckRoute^7: Walking directly to last node at '%v'", \ classname, m_vecLastNode); m_iCurNode = -1; } @@ -137,7 +137,7 @@ NSNavAI::CheckRoute(void) if (!trace_startsolid && trace_fraction == 1.0f) { evenpos = vecNextNode; m_iCurNode = iNextNode; - NSLog("^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); } } @@ -146,7 +146,7 @@ NSNavAI::CheckRoute(void) if (m_iCurNode < -1) { RouteClear(); RouteEnded(); - NSLog("^2%s::^3CheckRoute^7: %s reached end", classname, targetname); + NSNavAI_Log("^2%s::^3CheckRoute^7: %s reached end", classname, targetname); } /* crouch attempt */ @@ -234,11 +234,11 @@ NSNavAI::RouteToPosition(vector destination) /* can we walk directly to our target destination? */ if (trace_fraction == 1.0) { - NSLog("^2%s::^3RouteToPosition^7: " \ + NSNavAI_Log("^2%s::^3RouteToPosition^7: " \ "Walking directly to last node", classname); p.m_iCurNode = -1; } else { - NSLog("^2%s::^3RouteToPosition^7: " \ + NSNavAI_Log("^2%s::^3RouteToPosition^7: " \ "Path obstructed, calculating route", classname); /* run through all nodes, mark the closest direct path possible */ diff --git a/src/shared/NSSurfacePropEntity.h b/src/shared/NSSurfacePropEntity.h index 1b2027b1..af0a637c 100644 --- a/src/shared/NSSurfacePropEntity.h +++ b/src/shared/NSSurfacePropEntity.h @@ -14,6 +14,10 @@ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#ifdef CLIENT +noref .float health; +#endif + typedef enumflags { SRFENT_CHANGED_ORIGIN_X, @@ -47,6 +51,7 @@ private: float m_flBurnNext; PREDICTED_FLOAT(armor) + PREDICTED_FLOAT_N(health) #ifdef SERVER /* fire/burning */ diff --git a/src/shared/NSTalkMonster.qc b/src/shared/NSTalkMonster.qc index 676f6f59..e25b6c61 100644 --- a/src/shared/NSTalkMonster.qc +++ b/src/shared/NSTalkMonster.qc @@ -680,7 +680,8 @@ NSTalkMonster::SendEntity(entity ePEnt, float flChanged) SENDENTITY_COORD(maxs[1], MONFL_CHANGED_SIZE) SENDENTITY_COORD(maxs[2], MONFL_CHANGED_SIZE) SENDENTITY_BYTE(frame, MONFL_CHANGED_FRAME) - SENDENTITY_FLOAT(skin, MONFL_CHANGED_SKIN) + SENDENTITY_FLOAT(skin, MONFL_CHANGED_SKINHEALTH) + SENDENTITY_FLOAT(health, MONFL_CHANGED_SKINHEALTH) SENDENTITY_FLOAT(effects, MONFL_CHANGED_EFFECTS) SENDENTITY_BYTE(m_iBody, MONFL_CHANGED_BODY) SENDENTITY_FLOAT(scale, MONFL_CHANGED_SCALE) @@ -732,7 +733,7 @@ NSTalkMonster::ProcessWordQue(void) SentenceSample(m_pSentenceQue[m_iSentencePos].m_strSnd); - NSLog("^2NSEntity::^3ProcessWordQue^7: Speaking %s", m_pSentenceQue[m_iSentencePos].m_strSnd); + NSMonster_Log("^2NSEntity::^3ProcessWordQue^7: Speaking %s", m_pSentenceQue[m_iSentencePos].m_strSnd); m_iSentencePos++; if (m_iSentencePos == m_iSentenceCount) { @@ -856,7 +857,8 @@ NSTalkMonster::ReceiveEntity(float flNew, float flChanged) READENTITY_COORD(maxs[1], MONFL_CHANGED_SIZE) READENTITY_COORD(maxs[2], MONFL_CHANGED_SIZE) READENTITY_BYTE(frame, MONFL_CHANGED_FRAME) - READENTITY_FLOAT(skin, MONFL_CHANGED_SKIN) + READENTITY_FLOAT(skin, MONFL_CHANGED_SKINHEALTH) + READENTITY_FLOAT(health, MONFL_CHANGED_SKINHEALTH) READENTITY_FLOAT(effects, MONFL_CHANGED_EFFECTS) READENTITY_BYTE(m_iBody, MONFL_CHANGED_BODY) READENTITY_FLOAT(scale, MONFL_CHANGED_SCALE) @@ -899,14 +901,14 @@ NSTalkMonster_ParseSentence(void) if (ent) { if (ent.classname != "NSTalkMonster" && ent.classname != "ambient_generic") - NSLog("^3 NSTalkMonster_ParseSentence ^7: Entity %d not a NSTalkMonster!", e); + NSMonster_Log("^3 NSTalkMonster_ParseSentence ^7: Entity %d not a NSTalkMonster!", e); else { targ = (NSTalkMonster)ent; targ.Sentence(sentence); - NSLog("^3 NSTalkMonster_ParseSentence ^7: Entity %d saying %s", e, sentence); + NSMonster_Log("^3 NSTalkMonster_ParseSentence ^7: Entity %d saying %s", e, sentence); } } else { - NSLog("^3 NSTalkMonster_ParseSentence ^7: Entity %d not in PVS", e); + NSMonster_Log("^3 NSTalkMonster_ParseSentence ^7: Entity %d not in PVS", e); } } #endif