Half-Life: monster_zombie and monster_headcrab are attacking somewhat properly now and chase you around. Currently still working out the whole vision logic.

This commit is contained in:
Marco Cawthorne 2020-08-02 12:55:03 +02:00
parent 690d390e79
commit b9f4da2494
4 changed files with 165 additions and 33 deletions

View file

@ -24,8 +24,8 @@ typedef struct
enum enum
{ {
MONSTER_IDLE, MONSTER_IDLE,
MONSTER_DRAWING, MONSTER_FOLLOWING,
MONSTER_HOLSTERING, MONSTER_CHASING,
MONSTER_AIMING, MONSTER_AIMING,
MONSTER_DEAD, MONSTER_DEAD,
MONSTER_GIBBED MONSTER_GIBBED
@ -107,12 +107,16 @@ class CBaseMonster:CBaseEntity
virtual void(void) Gib; virtual void(void) Gib;
virtual void(string) Sound; virtual void(string) Sound;
/* see/hear subsystem */
float m_flSeeTime;
virtual void(void) SeeThink;
/* attack system */ /* attack system */
virtual void(void) AttackDraw; virtual void(void) AttackDraw;
virtual void(void) AttackHolster; virtual void(void) AttackHolster;
virtual void(void) AttackThink; virtual void(void) AttackThink;
virtual void(void) AttackMelee; virtual int(void) AttackMelee;
virtual void(void) AttackRanged; virtual int(void) AttackRanged;
/* sequences */ /* sequences */
virtual void(void) FreeState; 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 void
CBaseMonster::AttackThink(void) CBaseMonster::AttackThink(void)
{ {
@ -184,12 +221,9 @@ CBaseMonster::AttackThink(void)
return; return;
} }
/* don't have an enemy? let's look out for one */ /* reset */
if (!m_eEnemy) { if (m_eEnemy && m_eEnemy.health <= 0)
/* find code here */ m_eEnemy = __NULL__;
m_flAttackThink = time + 0.5f;
return;
}
/* do we have a clear shot? */ /* do we have a clear shot? */
other = world; other = world;
@ -197,7 +231,7 @@ CBaseMonster::AttackThink(void)
/* something is blocking us */ /* something is blocking us */
if (trace_fraction < 1.0f) { 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 */ /* FIXME: This is unreliable, but unlikely that a player ever is here */
if (m_vecLKPos != [0,0,0]) { if (m_vecLKPos != [0,0,0]) {
@ -206,41 +240,39 @@ CBaseMonster::AttackThink(void)
m_vecLKPos = [0,0,0]; m_vecLKPos = [0,0,0];
} }
} else { } else {
if (m_iMState == MONSTER_IDLE) { m_iMState = MONSTER_AIMING;
m_iMState = MONSTER_DRAWING;
} else if (m_iMState == MONSTER_DRAWING) {
m_iMState = MONSTER_AIMING;
}
/* make sure we remember the last known position. */ /* make sure we remember the last known position. */
m_vecLKPos = m_eEnemy.origin; m_vecLKPos = m_eEnemy.origin;
} }
if (m_iMState == MONSTER_AIMING) { if (m_iMState == MONSTER_AIMING) {
int m;
if (vlen(origin - m_eEnemy.origin) < 96) if (vlen(origin - m_eEnemy.origin) < 96)
AttackMelee(); m = AttackMelee();
else else {
AttackRanged(); m = AttackRanged();
} else if (m_iMState == MONSTER_DRAWING) {
AttackDraw(); /* if we don't have the desired attack mode, walk */
} else if (m_iMState == MONSTER_HOLSTERING) { if (m == FALSE)
AttackHolster(); m_iMState = MONSTER_CHASING;
m_iMState = MONSTER_IDLE;
}
} }
} }
void int
CBaseMonster::AttackMelee(void) CBaseMonster::AttackMelee(void)
{ {
dprint(sprintf("^1%s::AttackMelee: Not defined!\n", ::classname));
m_flAttackThink = time + 0.5f; m_flAttackThink = time + 0.5f;
return FALSE;
} }
void int
CBaseMonster::AttackRanged(void) CBaseMonster::AttackRanged(void)
{ {
dprint(sprintf("^1%s::AttackRanged: Not defined!\n", ::classname));
m_flAttackThink = time + 0.5f; m_flAttackThink = time + 0.5f;
return FALSE;
} }
void void
@ -380,6 +412,13 @@ CBaseMonster::WalkRoute(void)
input_angles[1] = endangles[1]; input_angles[1] = endangles[1];
input_movevalues = [m_flSequenceSpeed, 0, 0]; 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 void
@ -423,6 +462,7 @@ CBaseMonster::Physics(void)
input_angles = angles = v_angle = m_vecSequenceAngle; input_angles = angles = v_angle = m_vecSequenceAngle;
SetFrame(m_flSequenceEnd); SetFrame(m_flSequenceEnd);
} else if (movetype == MOVETYPE_WALK) { } else if (movetype == MOVETYPE_WALK) {
SeeThink();
AttackThink(); AttackThink();
CheckRoute(); CheckRoute();
WalkRoute(); WalkRoute();

View file

@ -58,8 +58,8 @@ class monster_barney:CBaseNPC
virtual void(void) AttackDraw; virtual void(void) AttackDraw;
virtual void(void) AttackHolster; virtual void(void) AttackHolster;
virtual void(void) AttackMelee; virtual int(void) AttackMelee;
virtual void(void) AttackRanged; virtual int(void) AttackRanged;
}; };
int int
@ -94,13 +94,13 @@ monster_barney::AttackHolster(void)
m_flAttackThink = m_flAnimTime; m_flAttackThink = m_flAnimTime;
} }
void int
monster_barney::AttackMelee(void) monster_barney::AttackMelee(void)
{ {
AttackRanged(); return AttackRanged();
} }
void int
monster_barney::AttackRanged(void) monster_barney::AttackRanged(void)
{ {
/* visual */ /* visual */
@ -110,6 +110,7 @@ monster_barney::AttackRanged(void)
/* functional */ /* functional */
TraceAttack_FireBullets(1, origin + [0,0,16], 8, [0.01,0,01], 2); TraceAttack_FireBullets(1, origin + [0,0,16], 8, [0.01,0,01], 2);
Sound_Play(this, CHAN_WEAPON, "weapon_glock.fire"); Sound_Play(this, CHAN_WEAPON, "weapon_glock.fire");
return TRUE;
} }
void void

View file

@ -61,6 +61,8 @@ class monster_headcrab:CBaseMonster
virtual int(void) AnimIdle; virtual int(void) AnimIdle;
virtual int(void) AnimWalk; virtual int(void) AnimWalk;
virtual int(void) AnimRun; virtual int(void) AnimRun;
virtual int(void) AttackRanged;
virtual void(void) touch;
}; };
int int
@ -81,6 +83,32 @@ monster_headcrab::AnimRun(void)
return HC_RUN; 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 void
monster_headcrab::Pain(int iHitBody) monster_headcrab::Pain(int iHitBody)
{ {
@ -149,5 +177,6 @@ monster_headcrab::monster_headcrab(void)
base_mins = [-16,-16,0]; base_mins = [-16,-16,0];
base_maxs = [16,16,36]; base_maxs = [16,16,36];
m_iAlliance = MAL_ALIEN;
CBaseMonster::CBaseMonster(); CBaseMonster::CBaseMonster();
} }

View file

@ -80,8 +80,69 @@ class monster_zombie:CBaseMonster
virtual void(int) Death; virtual void(int) Death;
virtual void(void) IdleNoise; virtual void(void) IdleNoise;
virtual void(void) Respawn; 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 void
monster_zombie::Pain(int iHitBody) monster_zombie::Pain(int iHitBody)
{ {
@ -160,5 +221,6 @@ monster_zombie::monster_zombie(void)
base_health = Skill_GetValue("zombie_health"); base_health = Skill_GetValue("zombie_health");
base_mins = [-16,-16,0]; base_mins = [-16,-16,0];
base_maxs = [16,16,72]; base_maxs = [16,16,72];
m_iAlliance = MAL_ALIEN;
CBaseMonster::CBaseMonster(); CBaseMonster::CBaseMonster();
} }