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
{
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();

View File

@ -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

View File

@ -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();
}

View File

@ -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();
}