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:
parent
690d390e79
commit
b9f4da2494
4 changed files with 165 additions and 33 deletions
|
@ -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();
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue