diff --git a/src/gs-entbase/server/basemonster.cpp b/src/gs-entbase/server/basemonster.cpp index 2151f25a..4730d63d 100644 --- a/src/gs-entbase/server/basemonster.cpp +++ b/src/gs-entbase/server/basemonster.cpp @@ -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; diff --git a/src/gs-entbase/server/basenpc.cpp b/src/gs-entbase/server/basenpc.cpp index 6aacfd04..b9751274 100644 --- a/src/gs-entbase/server/basenpc.cpp +++ b/src/gs-entbase/server/basenpc.cpp @@ -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; } diff --git a/src/server/valve/monster_alien_slave.cpp b/src/server/valve/monster_alien_slave.cpp index 155ca612..8f773401 100644 --- a/src/server/valve/monster_alien_slave.cpp +++ b/src/server/valve/monster_alien_slave.cpp @@ -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(); } diff --git a/src/server/valve/monster_barney.cpp b/src/server/valve/monster_barney.cpp index 7f4b6658..ec3934cb 100644 --- a/src/server/valve/monster_barney.cpp +++ b/src/server/valve/monster_barney.cpp @@ -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(); } diff --git a/src/server/valve/monster_bullchicken.cpp b/src/server/valve/monster_bullchicken.cpp index 718e8357..e0adf14b 100644 --- a/src/server/valve/monster_bullchicken.cpp +++ b/src/server/valve/monster_bullchicken.cpp @@ -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) { diff --git a/src/server/valve/monster_gargantua.cpp b/src/server/valve/monster_gargantua.cpp index 4212195d..ab7e39c1 100644 --- a/src/server/valve/monster_gargantua.cpp +++ b/src/server/valve/monster_gargantua.cpp @@ -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 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"); diff --git a/src/server/valve/monster_scientist.cpp b/src/server/valve/monster_scientist.cpp index 852732ab..fb65eebf 100644 --- a/src/server/valve/monster_scientist.cpp +++ b/src/server/valve/monster_scientist.cpp @@ -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(); }