diff --git a/src/gs-entbase/server/basemonster.cpp b/src/gs-entbase/server/basemonster.cpp index 04300331..27ced6a6 100644 --- a/src/gs-entbase/server/basemonster.cpp +++ b/src/gs-entbase/server/basemonster.cpp @@ -24,8 +24,8 @@ typedef struct enum { MONSTER_IDLE, - MONSTER_DRAWING, - MONSTER_HOLSTERING, + MONSTER_FOLLOWING, + MONSTER_CHASING, MONSTER_AIMING, MONSTER_DEAD, MONSTER_GIBBED @@ -107,12 +107,16 @@ class CBaseMonster:CBaseEntity virtual void(void) Gib; virtual void(string) Sound; + /* see/hear subsystem */ + float m_flSeeTime; + virtual void(void) SeeThink; + /* attack system */ virtual void(void) AttackDraw; virtual void(void) AttackHolster; virtual void(void) AttackThink; - virtual void(void) AttackMelee; - virtual void(void) AttackRanged; + virtual int(void) AttackMelee; + virtual int(void) AttackRanged; /* sequences */ virtual void(void) FreeState; @@ -177,6 +181,39 @@ CBaseMonster::IdleNoise(void) } +void +CBaseMonster::SeeThink(void) +{ + if (m_eEnemy) + return; + + if (m_flSeeTime > time) + return; + + m_flSeeTime = time + 0.25f; + + for (entity w = world; (w = find(w, ::classname, "player"));) { + + if (w.health <= 0) + continue; + + /* first, is the potential enemy in our field of view? */ + makevectors(angles); + vector v = normalize(w.origin - origin); + float flDot = v * v_forward; + + if (flDot < 0.60) + continue; + + other = world; + traceline(origin, w.origin, MOVE_OTHERONLY, this); + + if (trace_fraction == 1.0f) { + m_eEnemy = w; + return; + } + } +} void CBaseMonster::AttackThink(void) { @@ -184,12 +221,9 @@ CBaseMonster::AttackThink(void) return; } - /* don't have an enemy? let's look out for one */ - if (!m_eEnemy) { - /* find code here */ - m_flAttackThink = time + 0.5f; - return; - } + /* reset */ + if (m_eEnemy && m_eEnemy.health <= 0) + m_eEnemy = __NULL__; /* do we have a clear shot? */ other = world; @@ -197,7 +231,7 @@ CBaseMonster::AttackThink(void) /* something is blocking us */ if (trace_fraction < 1.0f) { - m_iMState = MONSTER_HOLSTERING; + m_iMState = MONSTER_IDLE; /* FIXME: This is unreliable, but unlikely that a player ever is here */ if (m_vecLKPos != [0,0,0]) { @@ -206,41 +240,39 @@ CBaseMonster::AttackThink(void) 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; - } + m_iMState = MONSTER_AIMING; /* make sure we remember the last known position. */ m_vecLKPos = m_eEnemy.origin; } if (m_iMState == MONSTER_AIMING) { + int m; 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; + m = AttackMelee(); + else { + m = AttackRanged(); + + /* if we don't have the desired attack mode, walk */ + if (m == FALSE) + m_iMState = MONSTER_CHASING; + + } } } -void +int CBaseMonster::AttackMelee(void) { - dprint(sprintf("^1%s::AttackMelee: Not defined!\n", ::classname)); m_flAttackThink = time + 0.5f; + return FALSE; } -void +int CBaseMonster::AttackRanged(void) { - dprint(sprintf("^1%s::AttackRanged: Not defined!\n", ::classname)); m_flAttackThink = time + 0.5f; + return FALSE; } void @@ -380,6 +412,13 @@ CBaseMonster::WalkRoute(void) input_angles[1] = endangles[1]; input_movevalues = [m_flSequenceSpeed, 0, 0]; } + + if (m_iMState == MONSTER_CHASING) { + /* we've got 'em in our sights, just need to walk closer */ + endangles = vectoangles(m_eEnemy.origin - origin); + input_movevalues = [140, 0, 0]; + input_angles[1] = endangles[1]; + } } void @@ -423,6 +462,7 @@ CBaseMonster::Physics(void) input_angles = angles = v_angle = m_vecSequenceAngle; SetFrame(m_flSequenceEnd); } else if (movetype == MOVETYPE_WALK) { + SeeThink(); AttackThink(); CheckRoute(); WalkRoute(); diff --git a/src/server/valve/monster_barney.cpp b/src/server/valve/monster_barney.cpp index fa6d1626..dc7d2005 100644 --- a/src/server/valve/monster_barney.cpp +++ b/src/server/valve/monster_barney.cpp @@ -58,8 +58,8 @@ class monster_barney:CBaseNPC virtual void(void) AttackDraw; virtual void(void) AttackHolster; - virtual void(void) AttackMelee; - virtual void(void) AttackRanged; + virtual int(void) AttackMelee; + virtual int(void) AttackRanged; }; int @@ -94,13 +94,13 @@ monster_barney::AttackHolster(void) m_flAttackThink = m_flAnimTime; } -void +int monster_barney::AttackMelee(void) { - AttackRanged(); + return AttackRanged(); } -void +int monster_barney::AttackRanged(void) { /* visual */ @@ -110,6 +110,7 @@ monster_barney::AttackRanged(void) /* functional */ TraceAttack_FireBullets(1, origin + [0,0,16], 8, [0.01,0,01], 2); Sound_Play(this, CHAN_WEAPON, "weapon_glock.fire"); + return TRUE; } void diff --git a/src/server/valve/monster_headcrab.cpp b/src/server/valve/monster_headcrab.cpp index 95a49f3b..ad89432f 100644 --- a/src/server/valve/monster_headcrab.cpp +++ b/src/server/valve/monster_headcrab.cpp @@ -61,6 +61,8 @@ class monster_headcrab:CBaseMonster virtual int(void) AnimIdle; virtual int(void) AnimWalk; virtual int(void) AnimRun; + virtual int(void) AttackRanged; + virtual void(void) touch; }; int @@ -81,6 +83,32 @@ monster_headcrab::AnimRun(void) return HC_RUN; } +int +monster_headcrab::AttackRanged(void) +{ + /* visual */ + if (random() < 0.5) + AnimPlay(HC_JUMP); + else + AnimPlay(HC_JUMP_VARIATION1); + + m_flAttackThink = m_flAnimTime; + Sound_Play(this, CHAN_VOICE, "monster_headcrab.attack"); + + /* functional */ + makevectors(vectoangles(m_eEnemy.origin - origin)); + velocity = v_forward * 512 + [0,0,250]; + return TRUE; +} + +void +monster_headcrab::touch(void) +{ + if (other.takedamage == DAMAGE_YES) + if (frame == HC_JUMP || frame == HC_JUMP_VARIATION1) + Damage_Apply(other, this, 500, 0, 0); +} + void monster_headcrab::Pain(int iHitBody) { @@ -149,5 +177,6 @@ monster_headcrab::monster_headcrab(void) base_mins = [-16,-16,0]; base_maxs = [16,16,36]; + m_iAlliance = MAL_ALIEN; CBaseMonster::CBaseMonster(); } diff --git a/src/server/valve/monster_zombie.cpp b/src/server/valve/monster_zombie.cpp index b82437be..b7173874 100644 --- a/src/server/valve/monster_zombie.cpp +++ b/src/server/valve/monster_zombie.cpp @@ -80,8 +80,69 @@ class monster_zombie:CBaseMonster virtual void(int) Death; virtual void(void) IdleNoise; virtual void(void) Respawn; + + virtual int(void) AnimIdle; + virtual int(void) AnimWalk; + virtual int(void) AnimRun; + + virtual int(void) AttackMelee; + virtual void(void) AttackFlail; }; + +int +monster_zombie::AnimIdle(void) +{ + return ZO_IDLE; +} + +int +monster_zombie::AnimWalk(void) +{ + return ZO_WALK; +} + +int +monster_zombie::AnimRun(void) +{ + return ZO_WALK; +} + +int +monster_zombie::AttackMelee(void) +{ + /* visual */ + if (random() < 0.5) + AnimPlay(ZO_ATTACK1); + else + AnimPlay(ZO_ATTACK2); + + m_flAttackThink = m_flAnimTime; + Sound_Play(this, CHAN_VOICE, "monster_zombie.attack"); + + /* functional */ + think = AttackFlail; + nextthink = 0.25f; + return TRUE; +} + +void +monster_zombie::AttackFlail(void) +{ + traceline(origin, m_eEnemy.origin, FALSE, this); + + if (trace_fraction >= 1.0 || trace_ent.takedamage != DAMAGE_YES) { + Sound_Play(this, CHAN_WEAPON, "monster_zombie.attackmiss"); + return; + } + + Damage_Apply(trace_ent, this, 25, 0, 0); + Sound_Play(this, CHAN_WEAPON, "monster_zombie.attackhit"); + + if (m_eEnemy.health <= 0) + m_eEnemy = __NULL__; +} + void monster_zombie::Pain(int iHitBody) { @@ -160,5 +221,6 @@ monster_zombie::monster_zombie(void) base_health = Skill_GetValue("zombie_health"); base_mins = [-16,-16,0]; base_maxs = [16,16,72]; + m_iAlliance = MAL_ALIEN; CBaseMonster::CBaseMonster(); }