2020-03-26 03:24:33 -07:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2016-2019 Marco Hladik <marco@icculus.org>
|
|
|
|
*
|
|
|
|
* Permission to use, copy, modify, and distribute this software for any
|
|
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
|
|
* copyright notice and this permission notice appear in all copies.
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
|
|
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
|
|
|
|
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
|
|
|
|
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
|
|
*/
|
|
|
|
|
2020-03-26 23:34:24 -07:00
|
|
|
|
2020-03-26 03:24:33 -07:00
|
|
|
/* NPCs are more advanced than regular monsters in that they express emotions
|
|
|
|
* and are able to interact more with the environment */
|
|
|
|
|
2020-03-26 23:34:24 -07:00
|
|
|
#define PLAYER_DETECT_RADIUS 512
|
|
|
|
|
|
|
|
enumflags
|
|
|
|
{
|
|
|
|
MONSTER_USED,
|
|
|
|
MONSTER_FEAR,
|
|
|
|
MONSTER_METPLAYER,
|
|
|
|
MONSTER_FALLING,
|
|
|
|
MONSTER_CANFOLLOW
|
|
|
|
};
|
|
|
|
|
2020-03-26 03:24:33 -07:00
|
|
|
class CBaseNPC:CBaseMonster
|
|
|
|
{
|
|
|
|
/* our NPCs can have a unique pitch to their voice */
|
|
|
|
float m_flPitch;
|
2020-03-26 23:34:24 -07:00
|
|
|
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;
|
2020-03-26 03:24:33 -07:00
|
|
|
|
|
|
|
/* sentences identifiers */
|
|
|
|
string m_talkAnswer; /* random answer to whenever a question is asked */
|
|
|
|
string m_talkAsk; /* asks a random generic question */
|
|
|
|
string m_talkAllyShot; /* asks to not shoot an ally further */
|
|
|
|
string m_talkGreet; /* greet other NPCs */
|
|
|
|
string m_talkIdle; /* idle chatter */
|
2020-03-26 23:34:24 -07:00
|
|
|
string m_talkHearing; /* what did we just hear? */
|
2020-03-26 03:24:33 -07:00
|
|
|
string m_talkSmelling; /* is something smelling bad? */
|
|
|
|
string m_talkStare; /* when NPC is being stared at */
|
|
|
|
string m_talkSurvived; /* we're near death */
|
|
|
|
string m_talkWounded; /* we've sustained light wounds */
|
|
|
|
|
|
|
|
/* things that NPCs will only say to the player */
|
|
|
|
string m_talkPlayerAsk; /* ask player some question */
|
|
|
|
string m_talkPlayerGreet; /* say hello to the player */
|
|
|
|
string m_talkPlayerIdle; /* idle chatter with the player */
|
|
|
|
string m_talkPlayerWounded1; /* slightly wounded player comment */
|
|
|
|
string m_talkPlayerWounded2; /* a bit worse */
|
|
|
|
string m_talkPlayerWounded3; /* yup, got thus far */
|
|
|
|
string m_talkUnfollow; /* when the player asks us to stop following */
|
|
|
|
string m_talkFollow; /* whenever player asks the NPC to follow */
|
|
|
|
string m_talkStopFollow; /* we have to stop following */
|
|
|
|
|
|
|
|
void() CBaseNPC;
|
|
|
|
virtual void(string) Speak;
|
|
|
|
virtual void(string) Sentence;
|
2020-03-26 23:34:24 -07:00
|
|
|
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;
|
2020-03-26 03:24:33 -07:00
|
|
|
};
|
|
|
|
|
2020-03-26 23:34:24 -07:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-26 03:24:33 -07:00
|
|
|
void
|
|
|
|
CBaseNPC::Sentence(string sentence)
|
|
|
|
{
|
|
|
|
string seq = Sentences_GetSamples(sentence);
|
|
|
|
|
|
|
|
if (seq == "") {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
|
|
|
|
WriteByte(MSG_MULTICAST, EV_SENTENCE);
|
|
|
|
WriteEntity(MSG_MULTICAST, this);
|
2020-03-26 04:19:27 -07:00
|
|
|
WriteString(MSG_MULTICAST, seq);
|
2020-03-26 03:24:33 -07:00
|
|
|
msg_entity = this;
|
|
|
|
multicast(origin, MULTICAST_PVS);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
CBaseNPC::Speak(string sentence)
|
|
|
|
{
|
|
|
|
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
|
|
|
|
WriteByte(MSG_MULTICAST, EV_SPEAK);
|
|
|
|
WriteEntity(MSG_MULTICAST, this);
|
|
|
|
WriteString(MSG_MULTICAST, sentence);
|
|
|
|
WriteFloat(MSG_MULTICAST, m_flPitch);
|
|
|
|
msg_entity = this;
|
|
|
|
multicast(origin, MULTICAST_PVS);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2020-03-26 23:34:24 -07:00
|
|
|
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)
|
2020-03-26 03:24:33 -07:00
|
|
|
{
|
2020-03-26 23:34:24 -07:00
|
|
|
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));
|
|
|
|
}
|
|
|
|
}
|
2020-03-26 03:24:33 -07:00
|
|
|
|
2020-03-26 23:34:24 -07:00
|
|
|
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;
|
2020-03-27 02:37:01 -07:00
|
|
|
CheckRoute();
|
|
|
|
WalkRoute();
|
2020-03-26 23:34:24 -07:00
|
|
|
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;
|
2020-03-26 03:24:33 -07:00
|
|
|
}
|