From 73597af3c016fd7005bd7d099672bcbebd92a63d Mon Sep 17 00:00:00 2001 From: Marco Hladik Date: Mon, 27 Jul 2020 01:19:53 +0200 Subject: [PATCH] Some basic Attack functions for CBaseMonster. monster_barney in Half-Life will draw, holster his weapon against targets and shoot. Shows there's some use in our pathfinding already. --- src/gs-entbase/client/baseentity.cpp | 1 + src/gs-entbase/server/basemonster.cpp | 156 ++++++++++++++++++++++++-- src/gs-entbase/server/basenpc.cpp | 1 + src/server/skill.c | 3 +- src/server/valve/monster_barney.cpp | 39 +++++++ 5 files changed, 187 insertions(+), 13 deletions(-) diff --git a/src/gs-entbase/client/baseentity.cpp b/src/gs-entbase/client/baseentity.cpp index 24646b4f..8b70dd15 100644 --- a/src/gs-entbase/client/baseentity.cpp +++ b/src/gs-entbase/client/baseentity.cpp @@ -279,6 +279,7 @@ void CBaseEntity::ReadEntity(float flChanged) } if (flChanged & BASEFL_CHANGED_FRAME) { frame1time = 0.0; + frame2time = 0.0f; frame = readbyte(); } if (flChanged & BASEFL_CHANGED_SKIN) { diff --git a/src/gs-entbase/server/basemonster.cpp b/src/gs-entbase/server/basemonster.cpp index 62ac3142..04300331 100644 --- a/src/gs-entbase/server/basemonster.cpp +++ b/src/gs-entbase/server/basemonster.cpp @@ -20,15 +20,18 @@ typedef struct int m_iFlags; } nodeslist_t; +/* movement states */ enum { MONSTER_IDLE, - MONSTER_WALK, - MONSTER_RUN, + MONSTER_DRAWING, + MONSTER_HOLSTERING, + MONSTER_AIMING, MONSTER_DEAD, - MONSTER_GIBBED, + MONSTER_GIBBED }; +/* scripted sequence states */ enum { SEQUENCESTATE_NONE, @@ -36,6 +39,7 @@ enum SEQUENCESTATE_ENDING }; +/* monster flags */ enumflags { MSF_WAITTILLSEEN, @@ -51,6 +55,15 @@ enumflags MSF_MULTIPLAYER }; +/* alliance state */ +enum +{ + MAL_FRIEND, /* friendly towards the player */ + MAL_ENEMY, /* unfriendly towards the player */ + MAL_ALIEN, /* unfriendly towards anyone but themselves */ + MAL_ROGUE /* no allies, not even amongst themselves */ +}; + class CBaseMonster:CBaseEntity { vector oldnet_velocity; @@ -60,23 +73,29 @@ class CBaseMonster:CBaseEntity vector base_maxs; int base_health; + /* sequences */ + string m_strRouteEnded; int m_iSequenceRemove; int m_iSequenceState; float m_flSequenceEnd; float m_flSequenceSpeed; vector m_vecSequenceAngle; + /* attack/alliance system */ + entity m_eEnemy; + float m_flFOV; + float m_flAttackThink; + int m_iAlliance; + int m_iMState; + vector m_vecLKPos; /* last-known pos */ + /* pathfinding */ int m_iNodes; int m_iCurNode; nodeslist_t *m_pRoute; vector m_vecLastNode; - /* sequences */ - string m_strRouteEnded; - void(void) CBaseMonster; - virtual void(void) touch; virtual void(void) Hide; virtual void(void) Respawn; @@ -88,9 +107,15 @@ class CBaseMonster:CBaseEntity virtual void(void) Gib; virtual void(string) Sound; + /* attack system */ + virtual void(void) AttackDraw; + virtual void(void) AttackHolster; + virtual void(void) AttackThink; + virtual void(void) AttackMelee; + virtual void(void) AttackRanged; + /* sequences */ virtual void(void) FreeState; - virtual void(void) ClearRoute; virtual void(void) CheckRoute; virtual void(void) WalkRoute; @@ -101,6 +126,7 @@ class CBaseMonster:CBaseEntity virtual int(void) AnimIdle; virtual int(void) AnimWalk; virtual int(void) AnimRun; + virtual void(float) AnimPlay; }; int @@ -121,6 +147,16 @@ CBaseMonster::AnimRun(void) return 0; } +void +CBaseMonster::AnimPlay(float seq) +{ + /* forces a client-side update */ + SendFlags |= BASEFL_CHANGED_FRAME; + + SetFrame(seq); + m_flAnimTime = time + frameduration(modelindex, frame); +} + void CBaseMonster::Sound(string msg) { @@ -141,6 +177,86 @@ CBaseMonster::IdleNoise(void) } +void +CBaseMonster::AttackThink(void) +{ + if (m_flAttackThink > time) { + return; + } + + /* don't have an enemy? let's look out for one */ + if (!m_eEnemy) { + /* find code here */ + m_flAttackThink = time + 0.5f; + return; + } + + /* do we have a clear shot? */ + other = world; + traceline(origin, m_eEnemy.origin, MOVE_OTHERONLY, this); + + /* something is blocking us */ + if (trace_fraction < 1.0f) { + m_iMState = MONSTER_HOLSTERING; + + /* FIXME: This is unreliable, but unlikely that a player ever is here */ + if (m_vecLKPos != [0,0,0]) { + NewRoute(m_vecLKPos); + m_flSequenceSpeed = 140; + m_vecLKPos = [0,0,0]; + } + } else { + if (m_iMState == MONSTER_IDLE) { + m_iMState = MONSTER_DRAWING; + } else if (m_iMState == MONSTER_DRAWING) { + m_iMState = MONSTER_AIMING; + } + + /* make sure we remember the last known position. */ + m_vecLKPos = m_eEnemy.origin; + } + + if (m_iMState == MONSTER_AIMING) { + if (vlen(origin - m_eEnemy.origin) < 96) + AttackMelee(); + else + AttackRanged(); + } else if (m_iMState == MONSTER_DRAWING) { + AttackDraw(); + } else if (m_iMState == MONSTER_HOLSTERING) { + AttackHolster(); + m_iMState = MONSTER_IDLE; + } +} + +void +CBaseMonster::AttackMelee(void) +{ + dprint(sprintf("^1%s::AttackMelee: Not defined!\n", ::classname)); + m_flAttackThink = time + 0.5f; +} + +void +CBaseMonster::AttackRanged(void) +{ + dprint(sprintf("^1%s::AttackRanged: Not defined!\n", ::classname)); + m_flAttackThink = time + 0.5f; +} + +void +CBaseMonster::AttackDraw(void) +{ + dprint(sprintf("^1%s::AttackDraw: Not defined!\n", ::classname)); + m_flAttackThink = time + 0.5f; +} + +void +CBaseMonster::AttackHolster(void) +{ + dprint(sprintf("^1%s::AttackHolster: Not defined!\n", ::classname)); + m_flAttackThink = time + 0.5f; +} + void CBaseMonster::ClearRoute(void) { @@ -203,7 +319,7 @@ CBaseMonster::CheckRoute(void) m_iCurNode--; velocity = [0,0,0]; /* clamp friction */ } - + if (m_iCurNode < -1) { ClearRoute(); dprint(sprintf("^2CBaseMonster::^3CheckRoute^7: %s reached end\n", this.m_strTargetName)); @@ -243,8 +359,18 @@ CBaseMonster::CheckRoute(void) void CBaseMonster::WalkRoute(void) { - if (m_iNodes) { - vector endangles; + vector endangles; + + /* we're busy shooting at something, don't walk */ + if (m_iMState == MONSTER_AIMING) { + endangles = vectoangles(m_eEnemy.origin - origin); + + /* TODO: lerp */ + input_angles[1] = endangles[1]; + return; + } + + if (m_iNodes && m_iMState == MONSTER_IDLE) { /* we're on our last node */ if (m_iCurNode < 0) { endangles = vectoangles(m_vecLastNode - origin); @@ -297,6 +423,7 @@ CBaseMonster::Physics(void) input_angles = angles = v_angle = m_vecSequenceAngle; SetFrame(m_flSequenceEnd); } else if (movetype == MOVETYPE_WALK) { + AttackThink(); CheckRoute(); WalkRoute(); runstandardplayerphysics(this); @@ -350,7 +477,8 @@ CBaseMonster::PlayerUse(void) void CBaseMonster::Pain(int iHitBody) { - + if (!m_eEnemy) + m_eEnemy = g_dmg_eAttacker; } void @@ -427,4 +555,8 @@ CBaseMonster::CBaseMonster(void) } CBaseEntity::CBaseEntity(); + + /* give us a 65 degree view cone */ + m_flFOV = 1.0 / 65; + m_iAlliance = MAL_ROGUE; } diff --git a/src/gs-entbase/server/basenpc.cpp b/src/gs-entbase/server/basenpc.cpp index 004b52e4..6d60081d 100644 --- a/src/gs-entbase/server/basenpc.cpp +++ b/src/gs-entbase/server/basenpc.cpp @@ -451,6 +451,7 @@ CBaseNPC::Physics(void) SetFrame(m_flSequenceEnd); } else { if (style != MONSTER_DEAD) { + AttackThink(); TalkPlayerGreet(); FollowChain(); diff --git a/src/server/skill.c b/src/server/skill.c index 0303fba2..45c85583 100644 --- a/src/server/skill.c +++ b/src/server/skill.c @@ -24,7 +24,8 @@ Skill_Init(void) readcmd(sprintf("exec skill_%s.cfg\n", cvar_string("game"))); } -float Skill_GetValue(string variable) +float +Skill_GetValue(string variable) { float skill = cvar("skill"); return cvar(sprintf("sk_%s%d", variable, skill)); diff --git a/src/server/valve/monster_barney.cpp b/src/server/valve/monster_barney.cpp index 6e0c88c5..fa6d1626 100644 --- a/src/server/valve/monster_barney.cpp +++ b/src/server/valve/monster_barney.cpp @@ -55,6 +55,11 @@ class monster_barney:CBaseNPC virtual int(void) AnimIdle; virtual int(void) AnimWalk; virtual int(void) AnimRun; + + virtual void(void) AttackDraw; + virtual void(void) AttackHolster; + virtual void(void) AttackMelee; + virtual void(void) AttackRanged; }; int @@ -75,6 +80,38 @@ monster_barney::AnimRun(void) return BA_RUN; } +void +monster_barney::AttackDraw(void) +{ + AnimPlay(BA_DRAW); + m_flAttackThink = m_flAnimTime; +} + +void +monster_barney::AttackHolster(void) +{ + AnimPlay(BA_HOLSTER); + m_flAttackThink = m_flAnimTime; +} + +void +monster_barney::AttackMelee(void) +{ + AttackRanged(); +} + +void +monster_barney::AttackRanged(void) +{ + /* visual */ + AnimPlay(BA_SHOOT1); + m_flAttackThink = time + 0.4f; + + /* functional */ + TraceAttack_FireBullets(1, origin + [0,0,16], 8, [0.01,0,01], 2); + Sound_Play(this, CHAN_WEAPON, "weapon_glock.fire"); +} + void monster_barney::PlayerUse(void) { @@ -89,6 +126,8 @@ monster_barney::PlayerUse(void) void monster_barney::Pain(int iHitBody) { + CBaseNPC::Pain(iHitBody); + WarnAllies(); if (m_flAnimTime > time) {