CBaseEntity/CBaseMonster: Add support for server-side model events. This enables models, as they sometimes do, to actually trigger entities in the world and much more. There's seperation between client-side and server-side events as well.

This commit is contained in:
Marco Cawthorne 2020-09-10 10:34:14 +02:00
parent 633ef19750
commit f4d4e86400
14 changed files with 278 additions and 188 deletions

View file

@ -149,9 +149,13 @@ CBaseEntity::predraw(void)
/* mouth flapping action */
bonecontrol5 = getchannellevel(this, CHAN_VOICE) * 20;
m_flBaseTime = frame1time;
frame1time += clframetime;
ProcessWordQue();
processmodelevents(modelindex, frame, m_flBaseTime,
frame1time, ModelEvent);
if (alpha > 0.0)
addentity(this);
@ -371,6 +375,23 @@ CBaseEntity::customphysics(void)
}
}
void
CBaseEntity::ModelEvent(float fTimeStamp, int iCode, string sData)
{
switch (iCode) {
case 1004:
sound(this, CHAN_BODY, sData, 1.0f, ATTN_NORM);
break;
/* things handled on the server-side */
case 1003:
break;
default:
dprint(sprintf("^3[CLIENT]^7 Unknown model-event code " \
"%i with data %s\n", iCode, sData));
break;
}
}
void CBaseEntity::Init(void)
{
isCSQC = TRUE;

View file

@ -29,6 +29,9 @@ class CBaseEntity
int m_iSentenceCount;
int m_iSentencePos;
/* model events */
float m_flBaseTime;
void(void) CBaseEntity;
virtual void(void) Init;
virtual void(void) Initialized;
@ -39,6 +42,7 @@ class CBaseEntity
virtual float(void) predraw;
virtual void(void) postdraw;
virtual void(void) customphysics;
virtual void(float, int, string) ModelEvent;
#ifdef GS_RENDERFX
virtual void(void) RenderFXPass;

View file

@ -287,6 +287,11 @@ CBaseEntity::SpawnInit(void)
for (int i = 1; i < (tokenize(__fullspawndata) - 1); i += 2) {
SpawnKey(argv(i), argv(i+1));
}
/* some entity might involuntarily call SpawnInit as part of being
a member of CBaseEntity. So we need to make sure that it doesn't
inherit stuff from the last previously loaded entity */
__fullspawndata = "";
}
void
@ -331,6 +336,9 @@ CBaseEntity::SpawnKey(string strKey, string strValue)
case "angles":
angles = stov(strValue);
break;
case "angle":
angles[1] = stof(strValue);
break;
case "solid":
solid = stof(strValue);
break;
@ -372,7 +380,12 @@ CBaseEntity::SpawnKey(string strKey, string strValue)
case "model":
model = strValue;
break;
case "classname":
case "spawnflags":
break;
default:
print(sprintf("^3%s^7::SpawnKey:: Unknown key '%s' with value '%s'\n",
classname, strKey, strValue));
break;
}
}

View file

@ -85,6 +85,9 @@ class CBaseMonster:CBaseEntity
vector m_vecSequenceAngle;
vector m_vecTurnAngle;
/* model events */
float m_flBaseTime;
/* attack/alliance system */
entity m_eEnemy;
float m_flFOV;
@ -109,6 +112,7 @@ class CBaseMonster:CBaseEntity
virtual void(void) IdleNoise;
virtual void(void) Gib;
virtual void(string) Sound;
virtual void(float, int, string) ModelEvent;
/* see/hear subsystem */
float m_flSeeTime;
@ -500,6 +504,31 @@ CBaseMonster::NewRoute(vector destination)
}
}
void
CBaseMonster::ModelEvent(float fTimeStamp, int iCode, string sData)
{
switch (iCode) {
case 1003:
for (entity f = world; (f = find(f, ::targetname, sData));) {
CBaseTrigger trigger = (CBaseTrigger)f;
if (trigger.Trigger != __NULL__) {
trigger.Trigger(this, TRIG_TOGGLE);
dprint(sprintf("^2%s^7::^3ModelEvent^7: " \
"Calling trigger '%s'\n",
classname, sData));
}
}
break;
/* things handled on the client-side */
case 1004:
break;
default:
dprint(sprintf("^3[SERVER]^7 Unknown model-event code " \
"%i with data %s\n", iCode, sData));
break;
}
}
void
CBaseMonster::Physics(void)
{

View file

@ -486,7 +486,6 @@ CBaseNPC::Physics(void)
CheckRoute();
WalkRoute();
runstandardplayerphysics(this);
Footsteps_Update();
SetOrigin(origin);
}
@ -504,7 +503,11 @@ CBaseNPC::Physics(void)
}
}
m_flBaseTime = frame1time;
frame1time += frametime;
processmodelevents(modelindex, frame, m_flBaseTime,
frame1time, ModelEvent);
}
void CBaseNPC::Respawn(void)

View file

@ -183,6 +183,5 @@ CBaseTrigger::SpawnKey(string strKey, string strValue)
void
CBaseTrigger::CBaseTrigger(void)
{
m_strMessage = "";
CBaseEntity::CBaseEntity();
}

View file

@ -18,9 +18,9 @@
"targetname" Name
"target" Target when triggered.
"killtarget" Target to kill when triggered.
"rendermode" Render-Mode the target changes to
"renderamt" Render-Alpha the target changes to
"rendercolor" Render-Color the target changes to
"rendermode" Render-Mode the target changes to.
"renderamt" Render-Alpha the target changes to.
"rendercolor" Render-Color the target changes to.
Changes the visual appearance of a target.
*/
@ -70,5 +70,5 @@ env_render::Trigger(entity act, int state)
void
env_render::env_render(void)
{
CBaseEntity::CBaseEntity();
CBaseTrigger::CBaseTrigger();
}

View file

@ -106,6 +106,7 @@ class armoury_entity:CBaseEntity
void(void) armoury_entity;
virtual void(void) touch;
virtual void(void) Respawn;
virtual void(string, string) SpawnKey;
};
void
@ -142,6 +143,31 @@ armoury_entity::Respawn(void)
droptofloor();
}
void
armoury_entity::SpawnKey(string strKey, string strValue)
{
switch (strKey) {
case "count":
m_iCount = stoi(strValue);
break;
case "item":
int id = stoi(strValue);
if (id < 0 || id >= 19) {
print(sprintf("^1armoury_entity with invalid item %i. ignoring\n", m_iItem));
remove(this);
return;
}
m_iItem = g_cstrike_armouryitems[id];
model = sArmouryModels[id];
break;
default:
CBaseEntity::SpawnKey(strKey, strValue);
break;
}
}
void
armoury_entity::armoury_entity(void)
{
@ -151,28 +177,5 @@ armoury_entity::armoury_entity(void)
}
m_iCount = 1;
for (int i = 1; i < (tokenize(__fullspawndata) - 1); i += 2) {
switch (argv(i)) {
case "count":
m_iCount = stoi(argv(i+1));
break;
case "item":
int id = stoi(argv(i+1));
if (id < 0 || id >= 19) {
print(sprintf("^1armoury_entity with invalid item %i. ignoring\n", m_iItem));
remove(this);
return;
}
m_iItem = g_cstrike_armouryitems[id];
model = sArmouryModels[id];
break;
default:
break;
}
}
CBaseEntity::CBaseEntity();
}

View file

@ -30,23 +30,27 @@ class monster_barney_dead:CBaseEntity
virtual void(void) Hide;
virtual void(void) Respawn;
virtual void(void) Gib;
virtual void(string, string) SpawnKey;
};
void monster_barney_dead::Gib(void)
void
monster_barney_dead::Gib(void)
{
takedamage = DAMAGE_NO;
FX_GibHuman(this.origin);
Hide();
}
void monster_barney_dead::Hide(void)
void
monster_barney_dead::Hide(void)
{
SetModel("");
solid = SOLID_NOT;
movetype = MOVETYPE_NONE;
}
void monster_barney_dead::Respawn(void)
void
monster_barney_dead::Respawn(void)
{
v_angle[0] = Math_FixDelta(m_oldAngle[0]);
v_angle[1] = Math_FixDelta(m_oldAngle[1]);
@ -65,20 +69,21 @@ void monster_barney_dead::Respawn(void)
SetFrame(35 + m_iPose);
}
void monster_barney_dead::monster_barney_dead(void)
void
monster_barney_dead::SpawnKey(string strKey, string strValue)
{
switch (strKey) {
case "pose":
m_iPose = stoi(strValue);
break;
default:
CBaseMonster::SpawnKey(strKey, strValue);
}
}
void
monster_barney_dead::monster_barney_dead(void)
{
model = "models/barney.mdl";
for (int i = 1; i < (tokenize(__fullspawndata)-1); i += 2) {
switch (argv(i)) {
case "pose":
m_iPose = stoi(argv(i+1));
default:
break;
}
}
CBaseEntity::CBaseEntity();
precache_model(m_oldModel);
Respawn();
CBaseMonster::CBaseMonster();
}

View file

@ -30,23 +30,27 @@ class monster_hevsuit_dead:CBaseMonster
virtual void(void) Hide;
virtual void(void) Respawn;
virtual void(void) Gib;
virtual void(string, string) SpawnKey;
};
void monster_hevsuit_dead::Gib(void)
void
monster_hevsuit_dead::Gib(void)
{
takedamage = DAMAGE_NO;
FX_GibHuman(this.origin);
Hide();
}
void monster_hevsuit_dead::Hide(void)
void
monster_hevsuit_dead::Hide(void)
{
SetModel("");
solid = SOLID_NOT;
movetype = MOVETYPE_NONE;
}
void monster_hevsuit_dead::Respawn(void)
void
monster_hevsuit_dead::Respawn(void)
{
v_angle[0] = Math_FixDelta(m_oldAngle[0]);
v_angle[1] = Math_FixDelta(m_oldAngle[1]);
@ -66,28 +70,28 @@ void monster_hevsuit_dead::Respawn(void)
SendFlags |= NPC_BODY;
}
void monster_hevsuit_dead::monster_hevsuit_dead(void)
void
monster_hevsuit_dead::SpawnKey(string strKey, string strValue)
{
switch (strKey) {
case "pose":
m_iPose = stoi(strValue);
break;
case "body":
SetBody(stoi(strValue) + 1);
break;
case "skin":
SetSkin(stoi(strValue));
break;
default:
CBaseMonster::SpawnKey(strKey, strValue);
}
}
void
monster_hevsuit_dead::monster_hevsuit_dead(void)
{
model = "models/player.mdl";
m_iBody = 2;
for (int i = 1; i < (tokenize(__fullspawndata)-1); i += 2) {
switch (argv(i)) {
case "pose":
m_iPose = stoi(argv(i+1));
break;
case "body":
SetBody(stoi(argv(i+1)) + 1);
break;
case "skin":
SetSkin(stoi(argv(i+1)));
break;
default:
break;
}
}
CBaseEntity::CBaseEntity();
precache_model(m_oldModel);
Respawn();
CBaseMonster::CBaseMonster();
}

View file

@ -30,23 +30,27 @@ class monster_hgrunt_dead:CBaseMonster
virtual void(void) Hide;
virtual void(void) Respawn;
virtual void(void) Gib;
virtual void(string, string) SpawnKey;
};
void monster_hgrunt_dead::Gib(void)
void
monster_hgrunt_dead::Gib(void)
{
takedamage = DAMAGE_NO;
FX_GibHuman(this.origin);
Hide();
}
void monster_hgrunt_dead::Hide(void)
void
monster_hgrunt_dead::Hide(void)
{
SetModel("");
solid = SOLID_NOT;
movetype = MOVETYPE_NONE;
}
void monster_hgrunt_dead::Respawn(void)
void
monster_hgrunt_dead::Respawn(void)
{
v_angle[0] = Math_FixDelta(m_oldAngle[0]);
v_angle[1] = Math_FixDelta(m_oldAngle[1]);
@ -66,27 +70,27 @@ void monster_hgrunt_dead::Respawn(void)
SendFlags |= NPC_BODY;
}
void monster_hgrunt_dead::monster_hgrunt_dead(void)
void
monster_hgrunt_dead::SpawnKey(string strKey, string strValue)
{
switch (strKey) {
case "pose":
m_iPose = stoi(strValue);
break;
case "body":
m_iBody = stoi(strValue) + 1;
break;
case "skin":
skin = stoi(strValue);
break;
default:
CBaseMonster::SpawnKey(strKey, strValue);
}
}
void
monster_hgrunt_dead::monster_hgrunt_dead(void)
{
model = "models/hgrunt.mdl";
for (int i = 1; i < (tokenize(__fullspawndata)-1); i += 2) {
switch (argv(i)) {
case "pose":
m_iPose = stoi(argv(i+1));
break;
case "body":
m_iBody = stoi(argv(i+1)) + 1;
break;
case "skin":
skin = stoi(argv(i+1));
break;
default:
break;
}
}
CBaseEntity::CBaseEntity();
precache_model(m_oldModel);
Respawn();
CBaseMonster::CBaseMonster();
}

View file

@ -80,6 +80,7 @@ class monster_scientist:CBaseNPC
virtual int(void) AnimIdle;
virtual int(void) AnimWalk;
virtual int(void) AnimRun;
virtual void(string, string) SpawnKey;
};
int
@ -152,6 +153,18 @@ monster_scientist::Respawn(void)
m_iFlags |= MONSTER_CANFOLLOW;
}
void
monster_scientist::SpawnKey(string strKey, string strValue)
{
switch (strKey) {
case "body":
SetBody(stoi(strValue) + 1);
break;
default:
CBaseEntity::SpawnKey(strKey, strValue);
}
}
void
monster_scientist::monster_scientist(void)
{
@ -187,48 +200,36 @@ monster_scientist::monster_scientist(void)
m_talkUnfollow = "!SC_WAIT";
m_talkFollow = "!SC_OK";
m_talkStopFollow = "!SC_STOP";
/* by default a random character etc. is chosen */
int body = -1;
for (int i = 1; i < (tokenize(__fullspawndata)-1); i += 2) {
switch (argv(i)) {
case "body":
body = stoi(argv(i+1)) + 1;
SetBody(body);
break;
default:
break;
}
}
m_iBody = -1;
model = "models/scientist.mdl";
base_mins = [-16,-16,0];
base_maxs = [16,16,72];
base_health = Skill_GetValue("scientist_health");
CBaseNPC::CBaseNPC();
/* has the body not been overriden, etc. choose a character for us */
if (body == -1) {
if (m_iBody == -1) {
SetBody((int)floor(random(1,5)));
}
switch (m_iBody) {
case 1:
m_flPitch = 105;
netname = "Walter";
break;
case 2:
m_flPitch = 100;
netname = "Einstein";
break;
case 3:
m_flPitch = 95;
netname = "Luther";
SetSkin(1);
break;
default:
m_flPitch = 100;
netname = "Slick";
case 1:
m_flPitch = 105;
netname = "Walter";
break;
case 2:
m_flPitch = 100;
netname = "Einstein";
break;
case 3:
m_flPitch = 95;
netname = "Luther";
SetSkin(1);
break;
default:
m_flPitch = 100;
netname = "Slick";
}
CBaseNPC::CBaseNPC();
}

View file

@ -41,23 +41,27 @@ class monster_scientist_dead:CBaseMonster
virtual void(void) Hide;
virtual void(void) Respawn;
virtual void(void) Gib;
virtual void(string, string) SpawnKey;
};
void monster_scientist_dead::Gib(void)
void
monster_scientist_dead::Gib(void)
{
takedamage = DAMAGE_NO;
FX_GibHuman(this.origin);
Hide();
}
void monster_scientist_dead::Hide(void)
void
monster_scientist_dead::Hide(void)
{
SetModel("");
solid = SOLID_NOT;
movetype = MOVETYPE_NONE;
}
void monster_scientist_dead::Respawn(void)
void
monster_scientist_dead::Respawn(void)
{
v_angle[0] = Math_FixDelta(m_oldAngle[0]);
v_angle[1] = Math_FixDelta(m_oldAngle[1]);
@ -101,27 +105,27 @@ void monster_scientist_dead::Respawn(void)
droptofloor();
}
void monster_scientist_dead::monster_scientist_dead(void)
void
monster_scientist_dead::SpawnKey(string strKey, string strValue)
{
switch (strKey) {
case "pose":
m_iPose = stoi(strValue);
break;
case "body":
SetBody(stoi(strValue) + 1);
break;
case "skin":
SetSkin(stoi(strValue));
break;
default:
CBaseMonster::SpawnKey(strKey, strValue);
}
}
void
monster_scientist_dead::monster_scientist_dead(void)
{
model = "models/scientist.mdl";
for (int i = 1; i < (tokenize(__fullspawndata)-1); i += 2) {
switch (argv(i)) {
case "pose":
m_iPose = stoi(argv(i+1));
break;
case "body":
m_iBody = stoi(argv(i+1)) + 1;
break;
case "skin":
skin = stoi(argv(i+1));
break;
default:
break;
}
}
CBaseEntity::CBaseEntity();
precache_model(m_oldModel);
Respawn();
CBaseMonster::CBaseMonster();
}

View file

@ -42,6 +42,7 @@ class monster_sitting_scientist:CBaseMonster
virtual void(void) Respawn;
virtual void(void) Death;
virtual void(void) Gib;
virtual void(string, string) SpawnKey;
};
void
@ -91,52 +92,51 @@ monster_sitting_scientist::Respawn(void)
droptofloor();
}
void
monster_sitting_scientist::SpawnKey(string strKey, string strValue)
{
switch (strKey) {
case "pose":
m_iPose = stoi(strValue);
break;
case "body":
SetBody(stoi(strValue) + 1);
break;
case "skin":
SetSkin(stoi(strValue));
break;
default:
CBaseMonster::SpawnKey(strKey, strValue);
}
}
void
monster_sitting_scientist::monster_sitting_scientist(void)
{
model = "models/scientist.mdl";
for (int i = 1; i < (tokenize(__fullspawndata)-1); i += 2) {
switch (argv(i)) {
case "pose":
m_iPose = stoi(argv(i+1));
break;
case "body":
m_iBody = stoi(argv(i+1)) + 1;
break;
case "skin":
skin = stoi(argv(i+1));
break;
default:
break;
}
}
CBaseMonster::CBaseMonster();
/* has the body not been overriden, etc. choose a character for us */
if (m_iBody == -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 */
m_iBody = floor(random(1,5));
SetBody((int)floor(random(1,5)));
}
switch (m_iBody) {
case 1:
m_flPitch = 105;
netname = "Walter";
break;
case 2:
m_flPitch = 100;
netname = "Einstein";
break;
case 3:
m_flPitch = 95;
netname = "Luther";
skin = 1;
break;
default:
m_flPitch = 100;
netname = "Slick";
case 1:
m_flPitch = 105;
netname = "Walter";
break;
case 2:
m_flPitch = 100;
netname = "Einstein";
break;
case 3:
m_flPitch = 95;
netname = "Luther";
SetSkin(1);
break;
default:
m_flPitch = 100;
netname = "Slick";
}
CBaseEntity::CBaseEntity();
precache_model(m_oldModel);
}