Simplified a lot of the Barney/Scientist code by expanding CBaseNPC

This commit is contained in:
Marco Cawthorne 2020-03-27 07:34:24 +01:00
parent dd16fd1684
commit bb0b4d8f6c
8 changed files with 927 additions and 825 deletions

View File

@ -21,6 +21,19 @@ enum {
MONSTER_DEAD
};
enumflags {
MSF_WAITTILLSEEN,
MSF_GAG,
MSF_MONSTERCLIP,
MSF_RESERVED1,
MSF_PRISONER,
MSF_RESERVED2,
MSF_RESERVED3,
MSF_WAITFORSCRIPT,
MSF_PREDISASTER,
MSF_FADECORPSE
};
class CBaseMonster:CBaseEntity
{
int body;

View File

@ -14,13 +14,36 @@
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/* NPCs are more advanced than regular monsters in that they express emotions
* and are able to interact more with the environment */
#define PLAYER_DETECT_RADIUS 512
enumflags
{
MONSTER_USED,
MONSTER_FEAR,
MONSTER_METPLAYER,
MONSTER_FALLING,
MONSTER_CANFOLLOW
};
class CBaseNPC:CBaseMonster
{
/* our NPCs can have a unique pitch to their voice */
float m_flPitch;
float m_flNextSentence;
int m_iFlags;
entity m_eFollowing;
entity m_eFollowingChain;
vector m_vecLastUserPos;
float m_flChangePath;
float m_flTraceTime;
/* damage/combat related */
float m_flPainTime;
/* sentences identifiers */
string m_talkAnswer; /* random answer to whenever a question is asked */
@ -28,6 +51,7 @@ class CBaseNPC:CBaseMonster
string m_talkAllyShot; /* asks to not shoot an ally further */
string m_talkGreet; /* greet other NPCs */
string m_talkIdle; /* idle chatter */
string m_talkHearing; /* what did we just hear? */
string m_talkSmelling; /* is something smelling bad? */
string m_talkStare; /* when NPC is being stared at */
string m_talkSurvived; /* we're near death */
@ -47,8 +71,69 @@ class CBaseNPC:CBaseMonster
void() CBaseNPC;
virtual void(string) Speak;
virtual void(string) Sentence;
virtual void() WarnAllies;
virtual void() FollowPlayer;
virtual void() FollowChain;
virtual void() Physics;
virtual int() AnimIdle;
virtual int() AnimWalk;
virtual int() AnimRun;
virtual void() PlayerUse;
virtual void() PanicFrame;
virtual void() Hide;
/*virtual void() TalkAnswer;
virtual void() TalkAsk;
virtual void() TalkAllyShot;
virtual void() TalkGreet;
virtual void() TalkIdle;
virtual void() TalkHearing;
virtual void() TalkSmelling;
virtual void() TalkStare;
virtual void() TalkSurvived;
virtual void() TalkWounded;*/
virtual void() TalkPlayerAsk;
virtual void() TalkPlayerGreet;
virtual void() TalkPlayerIdle;
virtual void() TalkPlayerWounded1;
virtual void() TalkPlayerWounded2;
virtual void() TalkPlayerWounded3;
virtual void() TalkUnfollow;
virtual void() TalkFollow;
virtual void() TalkStopFollow;
};
int
CBaseNPC::AnimIdle(void)
{
return 0;
}
int
CBaseNPC::AnimWalk(void)
{
return 0;
}
int
CBaseNPC::AnimRun(void)
{
return 0;
}
void
CBaseNPC::WarnAllies(void)
{
for (entity b = world; (b = find(b, ::classname, classname));) {
if (vlen(b.origin - origin) < PLAYER_DETECT_RADIUS) {
CBaseNPC w = (CBaseNPC)b;
w.m_iFlags |= MONSTER_METPLAYER;
w.m_eFollowing = world;
w.m_eFollowingChain = world;
}
}
}
void
CBaseNPC::Sentence(string sentence)
{
@ -78,8 +163,364 @@ CBaseNPC::Speak(string sentence)
multicast(origin, MULTICAST_PVS);
}
void
CBaseNPC::TalkPlayerGreet(void)
{
if (m_flNextSentence > time) {
return;
}
if (m_iFlags & MONSTER_METPLAYER) {
return;
}
for (entity p = world; (p = find(p, ::classname, "player"));) {
/* Find players in a specific radius */
if (vlen(p.origin - origin) < PLAYER_DETECT_RADIUS) {
/* If we can't physically see him, don't do anything */
traceline(origin, p.origin, FALSE, this);
if (trace_ent != p) {
continue;
}
Sentence(m_talkPlayerGreet);
m_flNextSentence = time + 10.0;
m_iFlags |= MONSTER_METPLAYER;
break;
}
}
}
void
CBaseNPC::TalkPlayerIdle(void)
{
if (spawnflags & MSF_PREDISASTER) {
return;
}
if (m_flNextSentence > time) {
return;
}
for (entity p = world; (p = find(p, ::classname, "player"));) {
/* Find players in a specific radius */
if (vlen(p.origin - origin) < PLAYER_DETECT_RADIUS) {
/* If we can't physically see him, don't do anything */
traceline(origin, p.origin, FALSE, this);
if (trace_ent != p) {
continue;
}
Sentence(m_talkPlayerIdle);
m_flNextSentence = time + 10.0;
break;
}
}
}
void
CBaseNPC::TalkPlayerAsk(void)
{
if (spawnflags & MSF_PREDISASTER) {
return;
}
if (m_flNextSentence > time) {
return;
}
for (entity p = world; (p = find(p, ::classname, "player"));) {
/* Find players in a specific radius */
if (vlen(p.origin - origin) < PLAYER_DETECT_RADIUS) {
/* If we can't physically see him, don't do anything */
traceline(origin, p.origin, FALSE, this);
if (trace_ent != p) {
continue;
}
Sentence(m_talkPlayerAsk);
m_flNextSentence = time + 10.0;
break;
}
}
}
void
CBaseNPC::TalkPlayerWounded1(void)
{
if (m_flNextSentence > time) {
return;
}
if (base_health < health) {
return;
}
for (entity p = world; (p = find(p, ::classname, "player"));) {
/* Find players in a specific radius */
if (vlen(p.origin - origin) < PLAYER_DETECT_RADIUS) {
/* If we can't physically see him, don't do anything */
traceline(origin, p.origin, FALSE, this);
if (trace_ent != p) {
continue;
}
Sentence(m_talkPlayerWounded3);
m_flNextSentence = time + 10.0;
break;
}
}
}
void
CBaseNPC::TalkPlayerWounded2(void)
{
if (m_flNextSentence > time) {
return;
}
if ((base_health / 2) < health) {
return;
}
for (entity p = world; (p = find(p, ::classname, "player"));) {
/* Find players in a specific radius */
if (vlen(p.origin - origin) < PLAYER_DETECT_RADIUS) {
/* If we can't physically see him, don't do anything */
traceline(origin, p.origin, FALSE, this);
if (trace_ent != p) {
continue;
}
Sentence(m_talkPlayerWounded3);
m_flNextSentence = time + 10.0;
break;
}
}
}
void
CBaseNPC::TalkPlayerWounded3(void)
{
if (m_flNextSentence > time) {
return;
}
for (entity p = world; (p = find(p, ::classname, "player"));) {
/* Find players in a specific radius */
if (vlen(p.origin - origin) < PLAYER_DETECT_RADIUS) {
/* If we can't physically see him, don't do anything */
traceline(origin, p.origin, FALSE, this);
if (trace_ent != p) {
continue;
}
Sentence(m_talkPlayerWounded3);
m_flNextSentence = time + 10.0;
break;
}
}
}
void
CBaseNPC::TalkUnfollow(void)
{
Sentence(m_talkUnfollow);
m_flNextSentence = time + 10.0;
}
void
CBaseNPC::TalkFollow(void)
{
Sentence(m_talkFollow);
m_flNextSentence = time + 10.0;
}
void
CBaseNPC::TalkStopFollow(void)
{
Sentence(m_talkStopFollow);
m_flNextSentence = time + 10.0;
}
void
CBaseNPC::FollowPlayer(void)
{
v_angle = vectoangles(m_eFollowingChain.origin - origin);
v_angle[0] = 0;
v_angle[1] = Math_FixDelta(v_angle[1]);
v_angle[2] = 0;
/* Give up after 1024 units */
if (vlen(m_eFollowingChain.origin - origin) > 1024) {
m_eFollowing = world;
} else if (vlen(m_eFollowingChain.origin - origin) > 64) {
input_movevalues[0] = 240;
other = world;
traceline(origin, m_eFollowingChain.origin, MOVE_OTHERONLY, this);
/* Tracing failed, there's world geometry in the way */
if (trace_fraction < 1.0f) {
v_angle = vectoangles(m_vecLastUserPos - origin);
v_angle[0] = 0;
v_angle[1] = Math_FixDelta(v_angle[1]);
v_angle[2] = 0;
} else {
m_vecLastUserPos = m_eFollowingChain.origin;
}
/* Trace again to see if another hostage is in our path and if so
* follow them instead, this makes pathing easier */
traceline(origin, /*mins, maxs,*/ m_vecLastUserPos, FALSE, this);
if (trace_ent.classname == classname) {
CBaseNPC que = (CBaseNPC)trace_ent;
if (que.m_eFollowingChain == m_eFollowing) {
if (trace_ent != this) {
m_eFollowingChain = trace_ent;
}
}
}
}
}
void
CBaseNPC::PanicFrame(void)
{
m_iFlags |= MONSTER_METPLAYER;
maxspeed = 240;
input_movevalues = [maxspeed, 0, 0];
if (m_flTraceTime < time) {
traceline(origin, origin + (v_forward * 64), FALSE, this);
if (trace_fraction < 1.0f) {
m_flChangePath = 0.0f;
}
m_flTraceTime = time + 0.5f;
}
if (m_flChangePath < time) {
float add;
vector pos;
pos = origin + [0,0,-18];
if (random() < 0.5) {
add = 45;
} else {
add = -45;
}
/* test every 45 degrees */
for (int i = 0; i < 8; i++) {
v_angle[1] = Math_FixDelta(v_angle[1] + add);
makevectors(v_angle);
traceline(pos, pos + (v_forward * 64), FALSE, this);
if (trace_fraction >= 1.0f) {
break;
}
}
m_flChangePath = time + floor(random(2,10));
}
}
void
CBaseNPC::FollowChain(void)
{
/* Deal with a hostage being rescued when it's following someone else */
if (m_eFollowingChain.classname == classname) {
if (m_eFollowingChain.solid == SOLID_NOT) {
m_eFollowingChain = m_eFollowing;
}
}
/* Deal with the hostage losing its rescuer (death) */
if (m_eFollowing.health <= 0) {
m_eFollowing = world;
}
}
void
CBaseNPC::Physics(void)
{
float spvel;
input_movevalues = [0,0,0];
input_impulse = 0;
input_buttons = 0;
if (style != MONSTER_DEAD) {
TalkPlayerGreet();
FollowChain();
if (m_eFollowing != world) {
FollowPlayer();
} else if (m_iFlags & MONSTER_FEAR) {
PanicFrame();
} else {
if (random() < 0.5) {
TalkPlayerAsk();
} else {
TalkPlayerIdle();
}
}
if (m_flPainTime > time) {
input_movevalues = [0,0,0];
} else {
spvel = vlen(velocity);
if (spvel < 5) {
frame = AnimIdle();
} else if (spvel <= 140) {
frame = AnimWalk();
} else if (spvel <= 240) {
frame = AnimRun();
}
}
}
input_angles = angles = v_angle;
input_timelength = frametime;
runstandardplayerphysics(this);
Footsteps_Update();
if (!(flags & FL_ONGROUND) && velocity[2] < -100) {
m_iFlags |= MONSTER_FALLING;
} else {
m_iFlags &= ~MONSTER_FALLING;
}
}
void
CBaseNPC::PlayerUse(void)
{
if (m_iFlags & MONSTER_FEAR) {
return;
}
/* can't press use any non-allies */
if (!(m_iFlags & MONSTER_CANFOLLOW)) {
return;
}
if ((m_eFollowing == world)) {
if (!(m_iFlags & MONSTER_USED)) {
m_iFlags |= MONSTER_USED;
}
TalkFollow();
m_eFollowing = eActivator;
m_eFollowingChain = m_eFollowing;
m_vecLastUserPos = m_eFollowing.origin;
} else {
TalkUnfollow();
m_eFollowing = world;
}
}
void
CBaseNPC::Hide(void)
{
m_eFollowing = world;
CBaseMonster::Hide();
}
void
CBaseNPC::CBaseNPC(void)
{
CBaseMonster::CBaseMonster();
m_eFollowing = world;
}

View File

@ -65,20 +65,35 @@ string slv_sndpain[] = {
"aslave/slv_pain2.wav"
};
class monster_alien_slave:CBaseMonster
class monster_alien_slave:CBaseNPC
{
float m_flIdleTime;
float m_flPainTime;
void() monster_alien_slave;
virtual void(int) Death;
virtual void(int) Pain;
virtual void(void) IdleChat;
virtual void(void) Respawn;
};
void
monster_alien_slave::IdleChat(void)
{
if (m_flIdleTime > time) {
return;
}
Sentence(m_talkIdle);
m_flIdleTime = time + 5.0f + random(0,20);
}
void
monster_alien_slave::Pain(int iHitBody)
{
CBaseMonster::Pain(iHitBody);
CBaseNPC::Pain(iHitBody);
if (m_flPainTime > time) {
return;
@ -116,13 +131,13 @@ monster_alien_slave::Death(int iHitBody)
}
/* set the functional differences */
CBaseMonster::Death(iHitBody);
CBaseNPC::Death(iHitBody);
}
void
monster_alien_slave::Respawn(void)
{
CBaseMonster::Respawn();
CBaseNPC::Respawn();
frame = SLV_IDLE;
}
@ -133,10 +148,30 @@ monster_alien_slave::monster_alien_slave(void)
precache_sound(slv_sndpain[i]);
}
m_talkAnswer = "";
m_talkAsk = "";
m_talkAllyShot = "";
m_talkGreet = "SLV_ALERT";
m_talkIdle = "!SLV_IDLE";
m_talkSmelling = "";
m_talkStare = "";
m_talkSurvived = "";
m_talkWounded = "";
m_talkPlayerAsk = "";
m_talkPlayerGreet = "!SLV_ALERT";
m_talkPlayerIdle = "";
m_talkPlayerWounded1 = "";
m_talkPlayerWounded2 = "";
m_talkPlayerWounded3 = "";
m_talkUnfollow = "";
m_talkFollow = "";
m_talkStopFollow = "";
netname = "Alien Slave";
model = "models/islave.mdl";
base_health = Skill_GetValue("islave_health");
base_mins = [-16,-16,0];
base_maxs = [16,16,72];
CBaseMonster::CBaseMonster();
CBaseNPC::CBaseNPC();
}

View File

@ -21,48 +21,33 @@ Barney Calhoun
*/
enum {
BARNEY_IDLE,
BARNEY_WALK,
BARNEY_RUN,
BARNEY_DEAD
BA_IDLE1,
BA_IDLE2,
BA_IDLE3,
BA_IDLE4,
BA_WALK,
BA_RUN,
BA_SHOOT1,
BA_SHOOT2,
BA_DRAW,
BA_HOLSTER,
BA_RELOAD,
BA_TURNLEFT,
BA_TURNRIGHT,
BA_FLINCH_LA,
BA_FLINCH_RA,
BA_FLINCH_LL,
BA_FLINCH_RL,
BA_FLINCH_SML
};
enum {
BARNA_IDLE1,
BARNA_IDLE2,
BARNA_IDLE3,
BARNA_IDLE4,
BARNA_WALK,
BARNA_RUN,
BARNA_SHOOT1,
BARNA_SHOOT2,
BARNA_DRAW,
BARNA_HOLSTER,
BARNA_RELOAD,
BARNA_TURNLEFT,
BARNA_TURNRIGHT,
BARNA_FLINCH_LA,
BARNA_FLINCH_RA,
BARNA_FLINCH_LL,
BARNA_FLINCH_RL,
BARNA_FLINCH_SML
};
enumflags
{
BARNF_USED,
BARNF_FEAR,
BARNF_SEEN,
BARNF_FALLING
};
string barney_snddie[] = {
string ba_snddie[] = {
"barney/ba_die1.wav",
"barney/ba_die1.wav",
"barney/ba_die2.wav"
};
string barney_sndpain[] = {
string ba_sndpain[] = {
"barney/ba_pain1.wav",
"barney/ba_pain1.wav",
"barney/ba_pain1.wav"
@ -70,211 +55,50 @@ string barney_sndpain[] = {
class monster_barney:CBaseNPC
{
vector m_vecLastUserPos;
entity m_eUser;
entity m_eRescuer;
float m_flPainTime;
float m_flChangePath;
float m_flTraceTime;
int m_iFlags;
void() monster_barney;
virtual void() touch;
virtual void() Hide;
virtual void() Respawn;
virtual void() PlayerUse;
virtual void(int) Pain;
virtual void(int) Death;
virtual void() Physics;
virtual void() WarnOthers;
virtual int() AnimIdle;
virtual int() AnimWalk;
virtual int() AnimRun;
};
void monster_barney::WarnOthers(void)
int
monster_barney::AnimIdle(void)
{
for (entity b = world; (b = find(b, ::classname, "monster_barney"));) {
if (vlen(b.origin - origin) < 512) {
monster_barney sci = (monster_barney)b;
sci.m_iFlags |= BARNF_SEEN;
sci.m_eUser = world;
sci.m_eRescuer = world;
}
}
return BA_IDLE1;
}
void monster_barney::Physics(void)
int
monster_barney::AnimWalk(void)
{
float spvel;
input_movevalues = [0,0,0];
input_impulse = 0;
input_buttons = 0;
if (style != BARNEY_DEAD) {
if (!(m_iFlags & BARNF_SEEN)) {
for (entity b = world; (b = find(b, ::classname, "player"));) {
/* Find players in a 256 unit radius */
if (vlen(b.origin - origin) < 256) {
/* If we can't physically see him, don't say hi. */
traceline(origin, b.origin, FALSE, this);
if (trace_ent != b) {
continue;
}
Sentence(m_talkPlayerGreet);
m_iFlags |= BARNF_SEEN;
break;
}
}
}
/* Deal with a hostage being rescued when it's following someone else */
if (m_eRescuer.classname == "monster_barney") {
if (m_eRescuer.solid == SOLID_NOT) {
m_eRescuer = m_eUser;
}
}
/* Deal with the hostage losing its rescuer (death) */
if (m_eUser.health <= 0) {
m_eUser = world;
}
if (m_eUser!= world) {
v_angle = vectoangles(m_eRescuer.origin - origin);
v_angle[0] = 0;
v_angle[1] = Math_FixDelta(v_angle[1]);
v_angle[2] = 0;
/* Give up after 1024 units */
if (vlen(m_eRescuer.origin - origin) > 1024) {
m_eUser = world;
} else if (vlen(m_eRescuer.origin - origin) > 64) {
input_movevalues[0] = 240;
other = world;
traceline(origin, /*mins, maxs, */m_eRescuer.origin, MOVE_OTHERONLY, this);
/* Tracing failed, there's world geometry in the way */
if (trace_fraction < 1.0f) {
v_angle = vectoangles(m_vecLastUserPos - origin);
v_angle[0] = 0;
v_angle[1] = Math_FixDelta(v_angle[1]);
v_angle[2] = 0;
} else {
m_vecLastUserPos = m_eRescuer.origin;
}
/* Trace again to see if another hostage is in our path and if so
* follow them instead, this makes pathing easier */
traceline(origin, /*mins, maxs,*/ m_vecLastUserPos, FALSE, this);
if (trace_ent.classname == "monster_barney") {
monster_barney que = (monster_barney)trace_ent;
if (que.m_eRescuer == m_eUser) {
if (trace_ent != this) {
m_eRescuer = trace_ent;
}
}
}
}
} else if (m_iFlags & BARNF_FEAR) {
m_iFlags |= BARNF_SEEN;
maxspeed = 240;
input_movevalues = [maxspeed, 0, 0];
if (m_flTraceTime < time) {
traceline(origin, origin + (v_forward * 64), FALSE, this);
if (trace_fraction < 1.0f) {
m_flChangePath = 0.0f;
}
m_flTraceTime = time + 0.5f;
}
if (m_flChangePath < time) {
float add;
vector pos;
pos = origin + [0,0,-18];
if (random() < 0.5) {
add = 45;
} else {
add = -45;
}
/* test every 45 degrees */
for (int i = 0; i < 8; i++) {
v_angle[1] = Math_FixDelta(v_angle[1] + add);
makevectors(v_angle);
traceline(pos, pos + (v_forward * 64), FALSE, this);
if (trace_fraction >= 1.0f) {
break;
}
}
m_flChangePath = time + floor(random(2,10));
}
} else {
//Sentence(m_talkPlayerIdle);
}
if (m_flPainTime > time) {
input_movevalues = [0,0,0];
} else {
spvel = vlen(velocity);
if (spvel < 5) {
frame = BARNA_IDLE1;
} else if (spvel <= 140) {
frame = BARNA_WALK;
} else if (spvel <= 240) {
frame = BARNA_RUN;
}
}
}
input_angles = angles = v_angle;
input_timelength = frametime;
runstandardplayerphysics(this);
Footsteps_Update();
if (!(flags & FL_ONGROUND) && velocity[2] < -100) {
m_iFlags |= BARNF_FALLING;
} else {
m_iFlags -= (flags & BARNF_FALLING);
}
return BA_WALK;
}
void monster_barney::touch(void)
int
monster_barney::AnimRun(void)
{
if (other.movetype == MOVETYPE_WALK) {
velocity = normalize(other.origin - origin) * -128;
}
return BA_RUN;
}
void monster_barney::PlayerUse(void)
void
monster_barney::PlayerUse(void)
{
if (m_iFlags & BARNF_FEAR) {
if (spawnflags & MSF_PREDISASTER) {
Sentence("!BA_POK");
return;
}
if ((m_eUser == world)) {
if (!(m_iFlags & BARNF_USED)) {
m_iFlags |= BARNF_USED;
}
Sentence(m_talkFollow);
m_eUser = eActivator;
m_eRescuer = m_eUser;
m_vecLastUserPos = m_eUser.origin;
} else {
Sentence(m_talkUnfollow);
m_eUser = world;
}
CBaseNPC::PlayerUse();
}
void monster_barney::Pain(int iHitBody)
void
monster_barney::Pain(int iHitBody)
{
WarnOthers();
WarnAllies();
if (m_flPainTime > time) {
return;
@ -284,94 +108,56 @@ void monster_barney::Pain(int iHitBody)
return;
}
int rand = floor(random(0,barney_sndpain.length));
Speak(barney_sndpain[rand]);
frame = BARNA_FLINCH_LA + floor(random(0, 5));
m_iFlags |= BARNF_FEAR;
int rand = floor(random(0,ba_sndpain.length));
Speak(ba_sndpain[rand]);
frame = BA_FLINCH_LA + floor(random(0, 5));
m_iFlags |= MONSTER_FEAR;
m_flPainTime = time + 0.25f;
}
void monster_barney::Death(int iHitBody)
void
monster_barney::Death(int iHitBody)
{
int r;
r = floor(random(0,barney_snddie.length));
Speak(barney_snddie[r]);
CBaseNPC::Death(iHitBody);
WarnOthers();
WarnAllies();
think = Respawn;
nextthink = time + 10.0f;
int r = floor(random(0,ba_snddie.length));
Speak(ba_snddie[r]);
m_eUser = world;
//customphysics = __NULL__;
m_iFlags = 0x0;
if (health < -50) {
Gib();
return;
}
flags &= ~FL_MONSTER;
movetype = MOVETYPE_NONE;
solid = SOLID_CORPSE;
if (style != BARNEY_DEAD) {
if (style != MONSTER_DEAD) {
frame = 25 + floor(random(0, 6));
style = BARNEY_DEAD;
style = MONSTER_DEAD;
}
}
void monster_barney::Hide(void)
void
monster_barney::Respawn(void)
{
setmodel(this, "");
m_eUser = world;
solid = SOLID_NOT;
movetype = MOVETYPE_NONE;
customphysics = __NULL__;
CBaseNPC::Respawn();
m_iFlags |= MONSTER_CANFOLLOW;
}
void monster_barney::Respawn(void)
void
monster_barney::monster_barney(void)
{
v_angle[0] = Math_FixDelta(m_oldAngle[0]);
v_angle[1] = Math_FixDelta(m_oldAngle[1]);
v_angle[2] = Math_FixDelta(m_oldAngle[2]);
flags |= FL_MONSTER;
setorigin(this, m_oldOrigin);
angles = v_angle;
solid = SOLID_SLIDEBOX;
movetype = MOVETYPE_WALK;
setmodel(this, m_oldModel);
setsize(this, VEC_HULL_MIN + [0,0,36], VEC_HULL_MAX + [0,0,36]);
m_eUser = world;
takedamage = DAMAGE_YES;
iBleeds = TRUE;
style = BARNEY_IDLE;
customphysics = Physics;
frame = BARNA_IDLE1;
SendFlags |= NPC_FRAME;
health = 50;
velocity = [0,0,0];
m_iFlags = 0x0;
SendFlags = 0xff;
}
void monster_barney::monster_barney(void)
{
for (int i = 0; i < barney_sndpain.length; i++) {
precache_sound(barney_sndpain[i]);
for (int i = 0; i < ba_sndpain.length; i++) {
precache_sound(ba_sndpain[i]);
}
for (int i = 0; i < barney_snddie.length; i++) {
precache_sound(barney_snddie[i]);
for (int i = 0; i < ba_snddie.length; i++) {
precache_sound(ba_snddie[i]);
}
/* TODO
* BA_MAD - When player gets too naughty
* */
m_talkAnswer = "!BA_ANSWER";
m_talkAsk = "";
m_talkAllyShot = "!BA_SCARED";
m_talkAsk = "!BA_QUESTION";
m_talkAllyShot = "!BA_SHOOT";
m_talkGreet = "";
m_talkIdle = "";
m_talkIdle = "!BA_IDLE";
m_talkHearing = "!BA_HEAR";
m_talkSmelling = "!BA_SMELL";
m_talkStare = "!BA_STARE";
m_talkSurvived = "!BA_WOUND";
@ -389,7 +175,8 @@ void monster_barney::monster_barney(void)
model = "models/barney.mdl";
netname = "Barney";
CBaseEntity::CBaseEntity();
precache_model(m_oldModel);
Respawn();
base_health = 50;
base_mins = [-16,-16,0];
base_maxs = [16,16,72];
CBaseNPC::CBaseNPC();
}

View File

@ -93,15 +93,35 @@ string bull_sndpain[] = {
class monster_bullchicken:CBaseMonster
{
float m_flIdleTime;
float m_flPainTime;
void() monster_bullchicken;
virtual void(int) Death;
virtual void(int) Pain;
virtual void(void) IdleNoise;
virtual void(void) Respawn;
};
void
monster_bullchicken::IdleNoise(void)
{
/* don't make noise if we're dead (corpse) */
if (style == MONSTER_DEAD) {
return;
}
if (m_flIdleTime > time) {
return;
}
/* timing needs to adjusted as sounds conflict */
m_flIdleTime = time + 2.0f + random(0,5);
int rand = floor(random(0, bull_sndidle.length));
Sound(bull_sndidle[rand]);
}
void
monster_bullchicken::Pain(int iHitBody)
{

View File

@ -45,15 +45,155 @@ enum {
GARG_BUST
};
/* Flame thrower sounds
* gar_flameoff1
* gar_flameon1
* gar_flamerun1 */
/* similar to bullsquid, groans during and after attacks */
string garg_sndattack[] = {
"garg/gar_attack1.wav",
"garg/gar_attack2.wav",
"garg/gar_attack3.wav"
};
string garg_sndalert[] = {
"garg/gar_alert1.wav",
"garg/gar_alert2.wav",
"garg/gar_alert3.wav"
};
string garg_snddie[] = {
"garg/gar_die1.wav",
"garg/gar_die2.wav"
};
string garg_sndidle[] = {
"garg/gar_idle1.wav",
"garg/gar_idle2.wav",
"garg/gar_idle3.wav",
"garg/gar_idle4.wav",
"garg/gar_idle5.wav",
"garg/gar_breathe1.wav",
"garg/gar_breathe2.wav",
"garg/gar_breathe3.wav"
};
/* has unique foot step sounds */
string garg_sndstep[] = {
"garg/gar_step1.wav",
"garg/gar_step2.wav"
};
string garg_sndpain[] = {
"garg/gar_pain1.wav",
"garg/gar_pain2.wav",
"garg/gar_pain3.wav"
};
class monster_gargantua:CBaseMonster
{
float m_flIdleTime;
float m_flPainTime;
void() monster_gargantua;
virtual void(int) Death;
virtual void(int) Pain;
virtual void(void) IdleNoise;
virtual void(void) Respawn;
};
void
monster_gargantua::IdleNoise(void)
{
/* don't make noise if we're dead (corpse) */
if (style == MONSTER_DEAD) {
return;
}
if (m_flIdleTime > time) {
return;
}
/* timing needs to adjusted as sounds conflict */
m_flIdleTime = time + 2.0f + random(0,5);
int rand = floor(random(0, garg_sndidle.length));
Sound(garg_sndidle[rand]);
}
void
monster_gargantua::Pain(int iHitBody)
{
CBaseMonster::Pain(iHitBody);
if (m_flPainTime > time) {
return;
}
if (random() < 0.25f) {
return;
}
int rand = floor(random(0,garg_sndpain.length));
Sound(garg_sndpain[rand]);
frame = (random() < 0.5) ? GARG_FLINCH : GARG_FLINCH2;
m_flPainTime = time + 0.25f;
}
void
monster_gargantua::Death(int iHitBody)
{
/* if we're already dead (corpse) don't change animations */
if (style != MONSTER_DEAD) {
frame = GARG_DIE;
/* the sound */
int rand = floor(random(0,garg_snddie.length));
Sound(garg_snddie[rand]);
}
/* set the functional differences */
CBaseMonster::Death(iHitBody);
}
void
monster_gargantua::Respawn(void)
{
CBaseMonster::Respawn();
frame = GARG_IDLE;
/* takes damage from explosives only
* takedamage = DAMAGE_NO; */
iBleeds = FALSE;
}
void monster_gargantua::monster_gargantua(void)
{
for (int i = 0; i <garg_sndalert.length; i++) {
precache_sound(garg_sndattack[i]);
}
for (int i = 0; i <garg_sndattack.length; i++) {
precache_sound(garg_sndattack[i]);
}
for (int i = 0; i < garg_snddie.length; i++) {
precache_sound(garg_snddie[i]);
}
for (int i = 0; i < garg_sndidle.length; i++) {
precache_sound(garg_sndidle[i]);
}
for (int i = 0; i < garg_sndpain.length; i++) {
precache_sound(garg_sndpain[i]);
}
for (int i = 0; i < garg_sndstep.length; i++) {
precache_sound(garg_sndstep[i]);
}
netname = "Gargantua";
model = "models/garg.mdl";
base_health = Skill_GetValue("gargantua_health");
base_mins = [-32,-32,0];
base_maxs = [32,32,128];
CBaseMonster::CBaseMonster();

View File

@ -32,7 +32,7 @@ enum {
GR_LEFTARMFLINCH,
GR_LAUNCHNADE,
GR_THROWNADE,
GR_IDLE1,
GR_IDLE,
GR_IDLE2,
GR_COMBATIDLE,
GR_FRONTKICK,
@ -122,13 +122,133 @@ string gr_sndpain[] = {
"hgrunt/gr_pain5.wav"
};
class monster_human_grunt:CBaseMonster
class monster_human_grunt:CBaseNPC
{
float m_flIdleTime;
float m_flPainTime;
void() monster_human_grunt;
virtual void() Scream;
virtual void() IdleChat;
virtual void() Respawn;
virtual void(int) Pain;
virtual void(int) Death;
};
void monster_human_grunt::Scream(void)
{
if (m_flIdleTime > time) {
return;
}
Sentence(m_talkAllyShot);
m_flIdleTime = time + 5.0f;
}
void monster_human_grunt::IdleChat(void)
{
if (m_flIdleTime > time) {
return;
}
Sentence(m_talkIdle);
/* Sentence(m_talkPlayerIdle); */
/* come up with logic to make them repsone to questions
* Sentence(m_talkAsk);
* Sentence(m_talkAnswer);
*/
m_flIdleTime = time + 5.0f + random(0,20);
}
void
monster_human_grunt::Pain(int iHitBody)
{
CBaseMonster::Pain(iHitBody);
if (m_flPainTime > time) {
return;
}
if (random() < 0.25f) {
return;
}
int rand = floor(random(0,gr_sndpain.length));
Sound(gr_sndpain[rand]);
frame = GR_FLINCH;
m_flPainTime = time + 0.25f;
}
void
monster_human_grunt::Death(int iHitBody)
{
/* if we're already dead (corpse) don't change animations */
if (style != MONSTER_DEAD) {
/* headshots == different animation */
/* this animation may not have been used, but it looks cool */
if (iHitBody == BODY_HEAD) {
if (random() < 0.5) {
frame = GR_DIEHS;
} else {
frame = GR_DIEBACK;
}
} else {
frame = GR_DIE;
}
}
/* set the functional differences */
CBaseMonster::Death(iHitBody);
}
void
monster_human_grunt::Respawn(void)
{
CBaseMonster::Respawn();
frame = GR_IDLE;
}
void monster_human_grunt::monster_human_grunt(void)
{
for (int i = 0; i < gr_sndpain.length; i++) {
precache_sound(gr_sndpain[i]);
}
for (int i = 0; i < gr_snddie.length; i++) {
precache_sound(gr_snddie[i]);
}
/* Adding some into other slots in hopes it feels right
* listed below are other setences that might need their own:
* !HG_MONST - Monster HG_ALERT
* !HG_GREN - Grenade toss
* !HG_CHECK - Sector check question
* !HG_CLEAR - Sector clear response */
m_talkAnswer = "!HG_ANSWER";
m_talkAsk = "!HG_QUEST";
m_talkAllyShot = "!HG_COVER";
m_talkGreet = "";
m_talkIdle = "!HG_IDLE";
m_talkSmelling = "";
m_talkStare = "";
m_talkSurvived = "!HG_CLEAR";
m_talkWounded = "!HG_CHECK";
m_talkPlayerAsk = "";
m_talkPlayerGreet = "!HG_ALERT";
m_talkPlayerIdle = "!HG_CHARGE";
m_talkPlayerWounded1 = "";
m_talkPlayerWounded2 = "";
m_talkPlayerWounded3 = "";
m_talkUnfollow = "";
m_talkFollow = "";
m_talkStopFollow = "";
netname = "Grunt";
model = "models/hgrunt.mdl";
base_health = Skill_GetValue("hgrunt_health");

View File

@ -20,13 +20,6 @@ Scientist
*/
enum {
MONSTER_IDLE,
MONSTER_WALK,
MONSTER_RUN,
MONSTER_DEAD
};
enum {
SCIA_WALK,
SCIA_WALKSCARED,
@ -73,15 +66,6 @@ enum {
SCIA_DEADTABLE3
};
enumflags
{
SCIF_USED,
SCIF_SCARED,
SCIF_FEAR,
SCIF_SEEN,
SCIF_FALLING
};
string sci_snddie[] = {
"scientist/sci_die1.wav",
"scientist/sci_die2.wav",
@ -89,110 +73,6 @@ string sci_snddie[] = {
"scientist/sci_die4.wav"
};
/* chat and idle sounds are handled via sentences.txt
* this should be deleted and redone at some point
*/
string sci_sndchitchat[] = {
"scientist/absolutely.wav",
"scientist/absolutelynot.wav",
"scientist/administrator.wav",
"scientist/alienappeal.wav",
"scientist/alientrick.wav",
"scientist/allnominal.wav",
"scientist/areyouthink.wav",
"scientist/asexpected.wav",
"scientist/beverage.wav",
"scientist/bloodsample.wav",
"scientist/cantbeserious.wav",
"scientist/chaostheory.wav",
"scientist/completelywrong.wav",
"scientist/containfail.wav",
"scientist/correcttheory.wav",
"scientist/dine.wav",
"scientist/dontknow.wav",
"scientist/donuteater.wav",
"scientist/doyousmell.wav",
"scientist/evergetout.wav",
"scientist/everseen.wav",
"scientist/fascinating.wav",
"scientist/goodpaper.wav",
"scientist/headcrab.wav",
"scientist/hideglasses.wav",
"scientist/hopenominal.wav",
"scientist/howinteresting.wav",
"scientist/hungryyet.wav",
"scientist/ibelieveso.wav",
"scientist/idontthinkso.wav",
"scientist/importantspecies.wav",
"scientist/improbable.wav",
"scientist/imsure.wav",
"scientist/inconclusive.wav",
"scientist/ipredictedthis.wav",
"scientist/justasked.wav",
"scientist/lambdalab.wav",
"scientist/limitsok.wav",
"scientist/lowervoice.wav",
"scientist/luckwillchange.wav",
"scientist/needsleep.wav",
"scientist/neverseen.wav",
"scientist/nodoubt.wav",
"scientist/nogrant.wav",
"scientist/noguess.wav",
"scientist/noidea.wav",
"scientist/noo.wav",
"scientist/notcertain.wav",
"scientist/nothostile.wav",
"scientist/notsure.wav",
"scientist/ofcourse.wav",
"scientist/ofcoursenot.wav",
"scientist/organicmatter.wav",
"scientist/perculiarmarks.wav",
"scientist/perculiarodor.wav",
"scientist/perhaps.wav",
"scientist/positively.wav",
"scientist/repeat.wav",
"scientist/reportflux.wav",
"scientist/rescueus.wav",
"scientist/ridiculous.wav",
"scientist/right.wav",
"scientist/rightway.wav",
"scientist/rumorclean.wav",
"scientist/runtest.wav",
"scientist/seencup.wav",
"scientist/shakeunification.wav",
"scientist/shutdownchart.wav",
"scientist/shutup.wav",
"scientist/simulation.wav",
"scientist/smellburning.wav",
"scientist/softethics.wav",
"scientist/stimulating.wav",
"scientist/stopasking.wav",
"scientist/thatsodd.wav",
"scientist/theoretically.wav",
"scientist/uselessphd.wav",
"scientist/waithere.wav",
"scientist/whatnext.wav",
"scientist/whocansay.wav",
"scientist/whoresponsible.wav",
"scientist/whyaskme.wav",
"scientist/yees.wav"
};
string sci_sndhear[] = {
"scientist/hearsomething.wav",
"scientist/startle1.wav",
"scientist/startle2.wav",
"scientist/startle3.wav",
"scientist/startle4.wav",
"scientist/startle5.wav",
"scientist/startle6.wav",
"scientist/startle7.wav",
"scientist/startle8.wav",
"scientist/startle9.wav",
"scientist/whatissound.wav"
};
string sci_sndpain[] = {
"scientist/sci_pain1.wav",
"scientist/sci_pain2.wav",
@ -206,359 +86,52 @@ string sci_sndpain[] = {
"scientist/sci_pain10.wav"
};
string sci_sndsee[] = {
"scientist/afellowsci.wav",
"scientist/ahfreeman.wav",
"scientist/freeman.wav",
"scientist/freemanalive.wav",
"scientist/goodtoseeyou.wav",
"scientist/greetings.wav",
"scientist/greetings2.wav",
"scientist/hello.wav",
"scientist/hellofreeman.wav",
"scientist/hellofromlab.wav",
"scientist/hellothere.wav",
"scientist/inmesstoo.wav",
"scientist/newhevsuit.wav"
};
string sci_sndscream[] = {
"scientist/scream1.wav",
"scientist/scream2.wav",
"scientist/scream3.wav",
"scientist/scream4.wav",
"scientist/dontwantdie.wav",
"scientist/scream5.wav",
"scientist/scream6.wav",
"scientist/scream7.wav",
"scientist/evergetout.wav",
//"scientist/scream8.wav",
//"scientist/scream9.wav",
"scientist/scream10.wav",
"scientist/scream11.wav",
"scientist/getoutalive.wav",
"scientist/scream12.wav",
"scientist/scream13.wav",
"scientist/scream14.wav",
"scientist/scream15.wav",
"scientist/scream16.wav",
"scientist/getoutofhere.wav",
"scientist/scream17.wav",
"scientist/scream18.wav",
"scientist/scream19.wav",
"scientist/gottogetout.wav",
"scientist/scream20.wav",
"scientist/scream21.wav",
"scientist/scream22.wav",
"scientist/youinsane.wav",
"scientist/scream23.wav",
"scientist/scream24.wav",
"scientist/scream25.wav",
"scientist/whatyoudoing.wav",
"scientist/canttakemore.wav",
"scientist/madness.wav",
"scientist/noplease.wav",
"scientist/getoutofhere.wav",
"scientist/sorryimleaving.wav",
};
string sci_sndstop[] = {
"scientist/stop1.wav",
"scientist/stop2.wav",
"scientist/stop3.wav",
"scientist/stop4.wav",
"scientist/sorryimleaving.wav"
};
string sci_snduse[] = {
"scientist/alright.wav",
"scientist/excellentteam.wav",
"scientist/fellowscientist.wav",
"scientist/fine.wav",
"scientist/hopeyouknow.wav",
"scientist/leadtheway.wav",
"scientist/letsgo.wav",
"scientist/yes3.wav",
"scientist/yesletsgo.wav"
};
string sci_snduseno[] = {
"scientist/beenaburden.wav",
"scientist/illwait.wav",
"scientist/illwaithere.wav",
"scientist/istay.wav",
"scientist/reconsider.wav",
"scientist/slowingyou.wav",
"scientist/whyleavehere.wav"
};
string sci_sndidle[] = {
"scientist/hideglasses.wav",
"scientist/weartie.wav",
"scientist/runtest.wav",
"scientist/limitsok.wav",
"scientist/asexpected.wav",
"scientist/thatsodd.wav",
"scientist/allnominal.wav",
"scientist/shutdownchart.wav",
"scientist/reportflux.wav",
"scientist/simulation.wav",
"scientist/hopenominal.wav",
};
class monster_scientist:CBaseNPC
{
vector m_vecLastUserPos;
entity m_eUser;
entity m_eRescuer;
float m_flScaredTime;
float m_flScreamTime;
float m_flPainTime;
float m_flChangePath;
float m_flTraceTime;
int m_iFlags;
void() monster_scientist;
virtual void() touch;
virtual void() Hide;
virtual void() Respawn;
virtual void() PlayerUse;
virtual void(int) Pain;
virtual void(int) Death;
virtual void() Physics;
virtual void() Scream;
virtual void() WarnOthers;
virtual void() IdleChat;
virtual int() AnimIdle;
virtual int() AnimWalk;
virtual int() AnimRun;
};
void monster_scientist::WarnOthers(void)
int
monster_scientist::AnimIdle(void)
{
for (entity b = world; (b = find(b, ::classname, "monster_scientist"));) {
if (vlen(b.origin - origin) < 512) {
monster_scientist sci = (monster_scientist)b;
sci.m_iFlags |= SCIF_SCARED | SCIF_FEAR | SCIF_SEEN;
sci.m_eUser = world;
sci.m_eRescuer = world;
sci.m_flScaredTime = time + 2.5f;
sci.Scream();
}
}
return SCIA_IDLE1;
}
void monster_scientist::Scream(void)
int
monster_scientist::AnimWalk(void)
{
if (m_flScreamTime > time) {
return SCIA_WALK;
}
int
monster_scientist::AnimRun(void)
{
return SCIA_RUN;
}
void
monster_scientist::PlayerUse(void)
{
if (spawnflags & MSF_PREDISASTER) {
Sentence("!SC_POK");
return;
}
int rand = floor(random(0,sci_sndscream.length));
Speak(sci_sndscream[rand]);
m_flScreamTime = time + 5.0f;
CBaseNPC::PlayerUse();
}
void monster_scientist::IdleChat(void)
void
monster_scientist::Pain(int iHitBody)
{
if (m_flScreamTime > time) {
return;
}
int rand = floor(random(0,sci_sndchitchat.length));
Speak(sci_sndchitchat[rand]);
m_flScreamTime = time + 5.0f + random(0,20);
}
void monster_scientist::Physics(void)
{
float spvel;
input_movevalues = [0,0,0];
input_impulse = 0;
input_buttons = 0;
if (style != MONSTER_DEAD) {
if (!(m_iFlags & SCIF_SEEN)) {
for (entity b = world; (b = find(b, ::classname, "player"));) {
/* Find players in a 256 unit radius */
if (vlen(b.origin - origin) < 256) {
/* If we can't physically see him, don't say hi. */
traceline(origin, b.origin, FALSE, this);
if (trace_ent != b) {
continue;
}
if (random() < 0.5) {
int rand = floor(random(0,sci_sndsee.length));
Speak(sci_sndsee[rand]);
}
m_iFlags |= SCIF_SEEN;
break;
}
}
}
/* Deal with a hostage being rescued when it's following someone else */
if (m_eRescuer.classname == "monster_scientist") {
if (m_eRescuer.solid == SOLID_NOT) {
m_eRescuer = m_eUser;
}
}
/* Deal with the hostage losing its rescuer (death) */
if (m_eUser.health <= 0) {
m_eUser = world;
}
if (m_eUser!= world) {
v_angle = vectoangles(m_eRescuer.origin - origin);
v_angle[0] = 0;
v_angle[1] = Math_FixDelta(v_angle[1]);
v_angle[2] = 0;
/* Give up after 1024 units */
if (vlen(m_eRescuer.origin - origin) > 1024) {
m_eUser = world;
} else if (vlen(m_eRescuer.origin - origin) > 64) {
input_movevalues[0] = 240;
other = world;
traceline(origin, /*mins, maxs, */m_eRescuer.origin, MOVE_OTHERONLY, this);
/* Tracing failed, there's world geometry in the way */
if (trace_fraction < 1.0f) {
v_angle = vectoangles(m_vecLastUserPos - origin);
v_angle[0] = 0;
v_angle[1] = Math_FixDelta(v_angle[1]);
v_angle[2] = 0;
} else {
m_vecLastUserPos = m_eRescuer.origin;
}
/* Trace again to see if another hostage is in our path and if so
* follow them instead, this makes pathing easier */
traceline(origin, /*mins, maxs,*/ m_vecLastUserPos, FALSE, this);
if (trace_ent.classname == "monster_scientist") {
monster_scientist que = (monster_scientist)trace_ent;
if (que.m_eRescuer == m_eUser) {
if (trace_ent != this) {
m_eRescuer = trace_ent;
}
}
}
}
} else if (m_iFlags & SCIF_FEAR) {
m_iFlags |= SCIF_SEEN;
Scream();
maxspeed = 240;
input_movevalues = [maxspeed, 0, 0];
if (m_flTraceTime < time) {
traceline(origin, origin + (v_forward * 64), FALSE, this);
if (trace_fraction < 1.0f) {
m_flChangePath = 0.0f;
}
m_flTraceTime = time + 0.5f;
}
if (m_flChangePath < time) {
float add;
vector pos;
pos = origin + [0,0,-18];
if (random() < 0.5) {
add = 45;
} else {
add = -45;
}
/* test every 45 degrees */
for (int i = 0; i < 8; i++) {
v_angle[1] = Math_FixDelta(v_angle[1] + add);
makevectors(v_angle);
traceline(pos, pos + (v_forward * 64), FALSE, this);
if (trace_fraction >= 1.0f) {
break;
}
}
m_flChangePath = time + floor(random(2,10));
}
} else {
IdleChat();
}
if (m_flScaredTime < time && m_iFlags & SCIF_SCARED) {
m_iFlags &= ~SCIF_SCARED;
}
if (m_flPainTime > time) {
input_movevalues = [0,0,0];
} else {
spvel = vlen(velocity);
if (spvel < 5) {
frame = (m_iFlags & SCIF_SCARED) ? SCIA_SCARED1:SCIA_IDLE1;
} else if (spvel <= 140) {
frame = (m_iFlags & SCIF_SCARED) ? SCIA_WALKSCARED:SCIA_WALK;
} else if (spvel <= 240) {
frame = (m_iFlags & SCIF_SCARED) ? SCIA_RUNSCARED:SCIA_RUN;
}
}
}
input_angles = angles = v_angle;
input_timelength = frametime;
runstandardplayerphysics(this);
Footsteps_Update();
if (!(flags & FL_ONGROUND) && velocity[2] < -100) {
if (!(m_iFlags & SCIF_FALLING)) {
Speak(sci_sndscream[0]);
}
m_iFlags |= SCIF_FALLING;
} else {
m_iFlags -= (flags & SCIF_FALLING);
}
}
void monster_scientist::touch(void)
{
if (other.movetype == MOVETYPE_WALK) {
velocity = normalize(other.origin - origin) * -128;
}
}
void monster_scientist::PlayerUse(void)
{
int r;
if (m_iFlags & SCIF_FEAR) {
return;
}
if ((m_eUser == world)) {
if (!(m_iFlags & SCIF_USED)) {
m_iFlags |= SCIF_USED;
}
r = floor(random(0,sci_snduse.length));
Speak(sci_snduse[r]);
m_eUser = eActivator;
m_eRescuer = m_eUser;
m_vecLastUserPos = m_eUser.origin;
} else {
r = floor(random(0,sci_snduseno.length));
Speak(sci_snduseno[r]);
m_eUser = world;
}
}
void monster_scientist::Pain(int iHitBody)
{
WarnOthers();
WarnAllies();
if (m_flPainTime > time) {
return;
@ -571,79 +144,36 @@ void monster_scientist::Pain(int iHitBody)
int rand = floor(random(0,sci_sndpain.length));
Speak(sci_sndpain[rand]);
frame = SCIA_FLINCH + floor(random(0, 5));
m_iFlags |= SCIF_FEAR;
frame = SCIA_FLINCH + floor(random(0, 6));
m_iFlags |= MONSTER_FEAR;
m_flPainTime = time + 0.25f;
}
void monster_scientist::Death(int iHitBody)
void
monster_scientist::Death(int iHitBody)
{
int r;
r = floor(random(0,sci_snddie.length));
CBaseNPC::Death(iHitBody);
WarnAllies();
int r = floor(random(0,sci_snddie.length));
Speak(sci_snddie[r]);
WarnOthers();
think = Respawn;
nextthink = time + 10.0f;
m_eUser = world;
//customphysics = __NULL__;
m_iFlags = 0x0;
if (health < -50) {
Gib();
return;
}
flags &= ~FL_MONSTER;
movetype = MOVETYPE_NONE;
solid = SOLID_CORPSE;
//takedamage = DAMAGE_NO;
if (style != MONSTER_DEAD) {
frame = SCIA_DIE_SIMPLE + floor(random(0, 6));
style = MONSTER_DEAD;
}
}
void monster_scientist::Hide(void)
void
monster_scientist::Respawn(void)
{
setmodel(this, "");
m_eUser = world;
solid = SOLID_NOT;
movetype = MOVETYPE_NONE;
customphysics = __NULL__;
CBaseNPC::Respawn();
m_iFlags |= MONSTER_CANFOLLOW;
}
void monster_scientist::Respawn(void)
{
v_angle[0] = Math_FixDelta(m_oldAngle[0]);
v_angle[1] = Math_FixDelta(m_oldAngle[1]);
v_angle[2] = Math_FixDelta(m_oldAngle[2]);
flags |= FL_MONSTER;
setorigin(this, m_oldOrigin);
angles = v_angle;
solid = SOLID_SLIDEBOX;
movetype = MOVETYPE_WALK;
setmodel(this, m_oldModel);
setsize(this, VEC_HULL_MIN + [0,0,36], VEC_HULL_MAX + [0,0,36]);
m_eUser = world;
takedamage = DAMAGE_YES;
iBleeds = TRUE;
style = MONSTER_IDLE;
customphysics = Physics;
frame = SCIA_IDLE1;
SendFlags |= NPC_FRAME;
health = 50;
velocity = [0,0,0];
m_iFlags = 0x0;
SendFlags = 0xff;
}
void monster_scientist::monster_scientist(void)
void
monster_scientist::monster_scientist(void)
{
for (int i = 0; i < sci_sndpain.length; i++) {
precache_sound(sci_sndpain[i]);
@ -651,22 +181,38 @@ void monster_scientist::monster_scientist(void)
for (int i = 0; i < sci_snddie.length; i++) {
precache_sound(sci_snddie[i]);
}
for (int i = 0; i < sci_sndscream.length; i++) {
precache_sound(sci_sndscream[i]);
}
for (int i = 0; i < sci_snduse.length; i++) {
precache_sound(sci_snduse[i]);
}
for (int i = 0; i < sci_snduseno.length; i++) {
precache_sound(sci_snduseno[i]);
}
for (int i = 0; i < sci_sndsee.length; i++) {
precache_sound(sci_sndsee[i]);
}
for (int i = 0; i < sci_sndidle.length; i++) {
precache_sound(sci_sndidle[i]);
if (spawnflags & MSF_PREDISASTER) {
m_talkAsk = "";
m_talkPlayerAsk = "!SC_PQUEST";
m_talkPlayerGreet = "!SC_PHELLO";
m_talkPlayerIdle = "!SC_PIDLE";
} else {
m_talkAsk = "!SC_QUESTION";
m_talkPlayerAsk = "!SC_QUESTION";
m_talkPlayerGreet = "!SC_HELLO";
m_talkPlayerIdle = "!SC_PIDLE";
}
m_talkAnswer = "!SC_ANSWER";
m_talkAllyShot = "!SC_PLFEAR";
m_talkGreet = "";
m_talkIdle = "!SC_IDLE";
m_talkHearing = "!SC_HEAR";
m_talkSmelling = "!SC_SMELL";
m_talkStare = "!SC_STARE";
m_talkSurvived = "!SC_WOUND";
m_talkWounded = "!SC_MORTAL";
/* they seem to use predisaster lines regardless of disaster state */
m_talkPlayerWounded1 = "!SC_CUREA";
m_talkPlayerWounded2 = "!SC_CUREB";
m_talkPlayerWounded3 = "!SC_CUREC";
m_talkUnfollow = "!SC_WAIT";
m_talkFollow = "!SC_OK";
m_talkStopFollow = "!SC_STOP";
/* by default a random character etc. is chosen */
body = -1;
for (int i = 1; i < (tokenize(__fullspawndata)-1); i += 2) {
switch (argv(i)) {
@ -679,13 +225,11 @@ void monster_scientist::monster_scientist(void)
}
model = "models/scientist.mdl";
CBaseEntity::CBaseEntity();
precache_model(m_oldModel);
Respawn();
base_mins = [-16,-16,0];
base_maxs = [16,16,72];
/* has the body not been overriden, etc. choose a character for us */
if (body == -1) {
/* This stuff needs to be persistent because we can't guarantee that
* the client-side geomset refresh happens. Don't shove this into Respawn */
body = floor(random(1,5));
}
@ -707,4 +251,6 @@ void monster_scientist::monster_scientist(void)
m_flPitch = 100;
netname = "Slick";
}
CBaseNPC::CBaseNPC();
}