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.

This commit is contained in:
Marco Cawthorne 2020-07-27 01:19:53 +02:00
parent da7c5a27e2
commit 73597af3c0
5 changed files with 187 additions and 13 deletions

View File

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

View File

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

View File

@ -451,6 +451,7 @@ CBaseNPC::Physics(void)
SetFrame(m_flSequenceEnd);
} else {
if (style != MONSTER_DEAD) {
AttackThink();
TalkPlayerGreet();
FollowChain();

View File

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

View File

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