CBaseTrigger: Added CBaseOutput, in preparation to support Source styled input/output mechanisms
This commit is contained in:
parent
9f95fd11c2
commit
dc47146e99
8 changed files with 325 additions and 38 deletions
|
@ -7,6 +7,7 @@ baseentity.h
|
|||
decals.h
|
||||
materials.h
|
||||
server/baseentity.cpp
|
||||
server/baseoutput.cpp
|
||||
server/basetrigger.cpp
|
||||
server/basemonster.cpp
|
||||
server/basenpc.cpp
|
||||
|
|
69
src/gs-entbase/server/baseoutput.cpp
Normal file
69
src/gs-entbase/server/baseoutput.cpp
Normal file
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* Copyright (c) 2016-2020 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.
|
||||
*/
|
||||
|
||||
/* inspired by https://developer.valvesoftware.com/wiki/Inputs_and_Outputs */
|
||||
|
||||
/* modern trigger architecture */
|
||||
class CBaseOutput:CBaseEntity
|
||||
{
|
||||
entity m_eActivator;
|
||||
string m_strTarget;
|
||||
string m_strInput;
|
||||
string m_strData;
|
||||
float m_flDelay;
|
||||
int m_iCount;
|
||||
int m_iOldCount;
|
||||
|
||||
void(void) CBaseOutput;
|
||||
virtual void(void) TriggerOutput;
|
||||
virtual void(void) SpawnInit;
|
||||
virtual void(void) Respawn;
|
||||
};
|
||||
|
||||
void
|
||||
CBaseOutput::TriggerOutput(void)
|
||||
{
|
||||
/* plug into all the inputs. */
|
||||
for (entity f = world; (f = find(f, ::targetname, m_strTarget));) {
|
||||
CBaseTrigger trigger = (CBaseTrigger)f;
|
||||
|
||||
if (trigger.Input != __NULL__) {
|
||||
trigger.Input(m_eActivator, m_strInput, m_strData);
|
||||
}
|
||||
}
|
||||
|
||||
/* we're not -1 (infinite) and we've still got one use to deduct */
|
||||
if (m_iCount > 0)
|
||||
m_iCount--;
|
||||
}
|
||||
|
||||
void
|
||||
CBaseOutput::SpawnInit(void)
|
||||
{
|
||||
/* EMPTY! */
|
||||
}
|
||||
|
||||
void
|
||||
CBaseOutput::Respawn(void)
|
||||
{
|
||||
m_iCount = m_iOldCount;
|
||||
}
|
||||
|
||||
void
|
||||
CBaseOutput::CBaseOutput(void)
|
||||
{
|
||||
gflags = GF_CANRESPAWN;
|
||||
}
|
|
@ -14,41 +14,87 @@
|
|||
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
enum
|
||||
{
|
||||
USE_TOGGLE,
|
||||
USE_CONTINOUS
|
||||
};
|
||||
|
||||
enum
|
||||
/* modern trigger architecture */
|
||||
void
|
||||
CBaseTrigger::UseOutput(entity act, string outname)
|
||||
{
|
||||
TRIG_OFF,
|
||||
TRIG_ON,
|
||||
TRIG_TOGGLE
|
||||
};
|
||||
for (entity f = world; (f = find(f, ::targetname, outname));) {
|
||||
CBaseOutput op = (CBaseOutput)f;
|
||||
/* no more tries and not -1 (infinite) */
|
||||
if (op.m_iCount == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
class CBaseTrigger:CBaseEntity
|
||||
op.m_eActivator = act;
|
||||
op.think = CBaseOutput::TriggerOutput;
|
||||
op.nextthink = time + op.m_flDelay;
|
||||
}
|
||||
}
|
||||
|
||||
/* input is a 4-5 parameter, commar separated string, output is the targetname
|
||||
of a minion entity that'll handle the triggering (and counting down of uses)
|
||||
as defined in the Source Input/Output specs */
|
||||
string
|
||||
CBaseTrigger::CreateOutput(string outmsg)
|
||||
{
|
||||
int m_strGlobalState;
|
||||
string m_strKillTarget;
|
||||
string m_strMessage;
|
||||
string m_strMaster;
|
||||
float m_flDelay;
|
||||
int m_iUseType;
|
||||
int m_iTeam;
|
||||
int m_iValue;
|
||||
static int outcount = 0;
|
||||
float c;
|
||||
|
||||
void(void) CBaseTrigger;
|
||||
if (!outmsg)
|
||||
return "";
|
||||
|
||||
virtual void(entity, int) Trigger;
|
||||
virtual void(entity, int) UseTargets;
|
||||
virtual void(entity, int, float) UseTargets_Delay;
|
||||
virtual int(void) GetValue;
|
||||
virtual int(void) GetMaster;
|
||||
virtual void(void) InitBrushTrigger;
|
||||
virtual void(void) InitPointTrigger;
|
||||
virtual void(string, string) SpawnKey;
|
||||
};
|
||||
string outname = sprintf("output_%i\n", outcount);
|
||||
outcount++;
|
||||
|
||||
c = tokenizebyseparator(outmsg, ",");
|
||||
for (float i = 1; i < c; i+=5) {
|
||||
CBaseOutput new_minion = spawn(CBaseOutput);
|
||||
|
||||
new_minion.classname = "triggerminion";
|
||||
new_minion.targetname = outname;
|
||||
new_minion.m_strTarget = substring(argv(i), 1,-1);
|
||||
new_minion.m_strInput = substring(argv(i+1), 1,-1);
|
||||
new_minion.m_strData = substring(argv(i+2), 1,-1);
|
||||
new_minion.m_flDelay = stof(substring(argv(i+3), 1,-1));
|
||||
new_minion.m_iCount = stoi(substring(argv(i+4), 1,-1));
|
||||
new_minion.m_iOldCount = new_minion.m_iCount;
|
||||
}
|
||||
|
||||
/* print final debug output */
|
||||
for (entity f = world; (f = find(f, ::targetname, outname));) {
|
||||
CBaseOutput new_minion = (CBaseOutput)f;
|
||||
print(sprintf("^2%s::OnTrigger report:\n", classname));
|
||||
print(sprintf("Target: %s\n", new_minion.m_strTarget));
|
||||
print(sprintf("Input: %s\n", new_minion.m_strInput));
|
||||
print(sprintf("Data Message: %s\n", new_minion.m_strData));
|
||||
print(sprintf("Delay: %f\n", new_minion.m_flDelay));
|
||||
print(sprintf("Uses: %i\n\n", new_minion.m_iCount));
|
||||
}
|
||||
|
||||
/* return the minion's name that'll act as the trigger */
|
||||
return outname;
|
||||
}
|
||||
|
||||
/* entities receive the inputs here and need to act on intype and data
|
||||
accordingly. this is just a stub for unknown event troubleshooting */
|
||||
void
|
||||
CBaseTrigger::Input(entity act, string intype, string data)
|
||||
{
|
||||
if (data != "")
|
||||
dprint(sprintf("^2%s::^3Input^7: Receives input %s from %s with data %s\n",
|
||||
this.classname, intype, act.classname, data));
|
||||
else
|
||||
dprint(sprintf("^2%s::^3Input^7: Receives input %s from %s\n",
|
||||
this.classname, intype, act.classname));
|
||||
}
|
||||
|
||||
/* legacy trigger architecture */
|
||||
void
|
||||
CBaseTrigger::Trigger(entity act, int state)
|
||||
{
|
||||
dprint(sprintf("^2%s::^3Input^7: Triggerd by %s with no consequence\n",
|
||||
this.classname, act.classname));
|
||||
}
|
||||
|
||||
void
|
||||
CBaseTrigger::UseTargets(entity act, int state)
|
||||
|
@ -136,12 +182,6 @@ CBaseTrigger::GetMaster(void)
|
|||
return t.GetValue();
|
||||
}
|
||||
|
||||
void
|
||||
CBaseTrigger::Trigger(entity act, int state)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
CBaseTrigger::InitPointTrigger(void)
|
||||
{
|
||||
|
@ -158,6 +198,48 @@ CBaseTrigger::InitBrushTrigger(void)
|
|||
SetRenderMode(RM_TRIGGER);
|
||||
}
|
||||
|
||||
void CompilerTest(void)
|
||||
{
|
||||
string outmsg = ",_control_retinal2,_BeginSequence,_,_0,_-1,_control_retinal3,_BeginSequence,_,_0,_-1,_control_retinal1,_BeginSequence,_,_0,_-1";
|
||||
|
||||
string out_targetname;
|
||||
string out_name;
|
||||
string out_in;
|
||||
string out_data;
|
||||
float out_delay;
|
||||
int out_uses;
|
||||
float c;
|
||||
static int outcount = 0;
|
||||
|
||||
out_targetname = sprintf("output_%i\n", outcount);
|
||||
outcount++;
|
||||
|
||||
c = tokenizebyseparator(outmsg, ",");
|
||||
for (float i = 1; i < c; i+=5) {
|
||||
out_name = substring(argv(i), 1,-1);
|
||||
out_in = substring(argv(i+1), 1,-1);
|
||||
out_data = substring(argv(i+2), 1,-1);
|
||||
out_delay = stof(substring(argv(i+3), 1,-1));
|
||||
out_uses = stoi(substring(argv(i+4), 1,-1));
|
||||
|
||||
print(sprintf("%d: %s\n", i, out_name));
|
||||
print(sprintf("%d: %s\n", i, out_in));
|
||||
print(sprintf("%d: %s\n", i, out_data));
|
||||
print(sprintf("%d: %d\n", i, out_delay));
|
||||
print(sprintf("%d: %i\n", i, out_uses));
|
||||
|
||||
CBaseOutput new_minion = spawn(CBaseOutput);
|
||||
new_minion.classname = "triggerminion";
|
||||
new_minion.targetname = out_targetname;
|
||||
new_minion.m_strTarget = out_name;
|
||||
new_minion.m_strInput = out_in;
|
||||
new_minion.m_strData = out_data;
|
||||
new_minion.m_flDelay = out_delay;
|
||||
new_minion.m_iCount = out_uses;
|
||||
new_minion.m_iOldCount = out_uses;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CBaseTrigger::SpawnKey(string strKey, string strValue)
|
||||
{
|
||||
|
@ -177,6 +259,10 @@ CBaseTrigger::SpawnKey(string strKey, string strValue)
|
|||
case "delay":
|
||||
m_flDelay = stof(strValue);
|
||||
break;
|
||||
case "OnTrigger":
|
||||
strValue = strreplace(",", ",_", strValue);
|
||||
m_strOnTrigger = strcat(m_strOnTrigger, ",_", strValue);
|
||||
break;
|
||||
default:
|
||||
CBaseEntity::SpawnKey(strKey, strValue);
|
||||
break;
|
||||
|
@ -187,4 +273,6 @@ void
|
|||
CBaseTrigger::CBaseTrigger(void)
|
||||
{
|
||||
CBaseEntity::CBaseEntity();
|
||||
|
||||
m_strOnTrigger = CreateOutput(m_strOnTrigger);
|
||||
}
|
||||
|
|
63
src/gs-entbase/server/basetrigger.h
Normal file
63
src/gs-entbase/server/basetrigger.h
Normal file
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* Copyright (c) 2016-2020 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.
|
||||
*/
|
||||
|
||||
enum
|
||||
{
|
||||
USE_TOGGLE,
|
||||
USE_CONTINOUS
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
TRIG_OFF,
|
||||
TRIG_ON,
|
||||
TRIG_TOGGLE
|
||||
};
|
||||
|
||||
class CBaseTrigger:CBaseEntity
|
||||
{
|
||||
int m_strGlobalState;
|
||||
string m_strKillTarget;
|
||||
string m_strMessage;
|
||||
string m_strMaster;
|
||||
int m_iUseType;
|
||||
int m_iTeam;
|
||||
int m_iValue;
|
||||
|
||||
void(void) CBaseTrigger;
|
||||
|
||||
/* modern trigger architecture */
|
||||
string m_strOnTrigger;
|
||||
virtual void(entity, string) UseOutput;
|
||||
virtual string(string) CreateOutput;
|
||||
virtual void(entity, string, string) Input;
|
||||
|
||||
/* legacy trigger architecture */
|
||||
float m_flDelay;
|
||||
virtual void(entity, int) Trigger;
|
||||
virtual void(entity, int) UseTargets;
|
||||
virtual void(entity, int, float) UseTargets_Delay;
|
||||
|
||||
/* master feature */
|
||||
virtual int(void) GetValue;
|
||||
virtual int(void) GetMaster;
|
||||
|
||||
/* spawn setup helpers */
|
||||
virtual void(void) InitBrushTrigger;
|
||||
virtual void(void) InitPointTrigger;
|
||||
|
||||
virtual void(string, string) SpawnKey;
|
||||
};
|
|
@ -15,6 +15,7 @@
|
|||
*/
|
||||
|
||||
#include "baseentity.h"
|
||||
#include "basetrigger.h"
|
||||
|
||||
void FX_Spark(vector, vector);
|
||||
void FX_BreakModel(int, vector, vector, vector, float);
|
||||
|
|
|
@ -36,8 +36,9 @@ enumflags
|
|||
|
||||
class trigger_multiple:CBaseTrigger
|
||||
{
|
||||
float m_flDelay;
|
||||
float m_flWait;
|
||||
string m_strOnStartTouch;
|
||||
|
||||
void(void) trigger_multiple;
|
||||
virtual void(void) touch;
|
||||
virtual void(void) Respawn;
|
||||
|
@ -61,6 +62,13 @@ trigger_multiple::touch(void)
|
|||
}
|
||||
}
|
||||
|
||||
/* modern */
|
||||
if (!target) {
|
||||
UseOutput(other, m_strOnStartTouch);
|
||||
return;
|
||||
}
|
||||
|
||||
/* legacy */
|
||||
if (m_flDelay > 0) {
|
||||
UseTargets_Delay(other, TRIG_TOGGLE, m_flDelay);
|
||||
} else {
|
||||
|
@ -88,6 +96,11 @@ trigger_multiple::SpawnKey(string strKey, string strValue)
|
|||
case "wait":
|
||||
m_flWait = stof(strValue);
|
||||
break;
|
||||
case "OnStartTouch":
|
||||
case "OnStartTouchAll":
|
||||
strValue = strreplace(",", ",_", strValue);
|
||||
m_strOnStartTouch = strcat(m_strOnStartTouch, ",_", strValue);
|
||||
break;
|
||||
default:
|
||||
CBaseTrigger::SpawnKey(strKey, strValue);
|
||||
}
|
||||
|
@ -97,4 +110,7 @@ void
|
|||
trigger_multiple::trigger_multiple(void)
|
||||
{
|
||||
CBaseTrigger::CBaseTrigger();
|
||||
|
||||
if (m_strOnStartTouch)
|
||||
m_strOnStartTouch = CreateOutput(m_strOnStartTouch);
|
||||
}
|
||||
|
|
|
@ -35,10 +35,13 @@ enumflags
|
|||
|
||||
class trigger_once:CBaseTrigger
|
||||
{
|
||||
string m_strOnStartTouch;
|
||||
|
||||
void(void) trigger_once;
|
||||
|
||||
virtual void(void) touch;
|
||||
virtual void(void) Respawn;
|
||||
virtual void(string, string) SpawnKey;
|
||||
};
|
||||
|
||||
void
|
||||
|
@ -54,6 +57,11 @@ trigger_once::touch(void)
|
|||
solid = SOLID_NOT; /* make inactive */
|
||||
m_iValue = 1;
|
||||
|
||||
if (!target) {
|
||||
UseOutput(other, m_strOnStartTouch);
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_flDelay > 0) {
|
||||
CBaseTrigger::UseTargets_Delay(other, TRIG_TOGGLE, m_flDelay);
|
||||
} else {
|
||||
|
@ -70,8 +78,25 @@ trigger_once::Respawn(void)
|
|||
InitBrushTrigger();
|
||||
}
|
||||
|
||||
void
|
||||
trigger_once::SpawnKey(string strKey, string strValue)
|
||||
{
|
||||
switch (strKey) {
|
||||
case "OnStartTouch":
|
||||
strValue = strreplace(",", ",_", strValue);
|
||||
m_strOnStartTouch = strcat(m_strOnStartTouch, ",_", strValue);
|
||||
break;
|
||||
default:
|
||||
CBaseTrigger::SpawnKey(strKey, strValue);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
trigger_once::trigger_once(void)
|
||||
{
|
||||
CBaseTrigger::CBaseTrigger();
|
||||
|
||||
if (m_strOnStartTouch)
|
||||
m_strOnStartTouch = CreateOutput(m_strOnStartTouch);
|
||||
}
|
||||
|
|
|
@ -24,10 +24,13 @@ Provides the player with armor, a flashlight and a Heads-Up-Display.
|
|||
*/
|
||||
class item_suit:CBaseTrigger
|
||||
{
|
||||
string m_strOnPlayerTouch;
|
||||
|
||||
void(void) item_suit;
|
||||
|
||||
virtual void(void) touch;
|
||||
virtual void(void) Respawn;
|
||||
virtual void(string, string) SpawnKey;
|
||||
};
|
||||
|
||||
void item_suit::touch(void)
|
||||
|
@ -47,7 +50,12 @@ void item_suit::touch(void)
|
|||
pl.g_items |= ITEM_SUIT;
|
||||
m_iValue = TRUE;
|
||||
|
||||
CBaseTrigger::UseTargets(other, TRIG_TOGGLE);
|
||||
if (!target) {
|
||||
UseOutput(other, m_strOnPlayerTouch);
|
||||
return;
|
||||
} else {
|
||||
CBaseTrigger::UseTargets(other, TRIG_TOGGLE);
|
||||
}
|
||||
|
||||
if (real_owner || cvar("sv_playerslots") == 1) {
|
||||
remove(self);
|
||||
|
@ -74,6 +82,20 @@ void item_suit::Respawn(void)
|
|||
Sound_Play(this, CHAN_ITEM, "item.respawn");
|
||||
}
|
||||
|
||||
void
|
||||
item_suit::SpawnKey(string strKey, string strValue)
|
||||
{
|
||||
switch (strKey) {
|
||||
case "OnPlayerTouch":
|
||||
strValue = strreplace(",", ",_", strValue);
|
||||
m_strOnPlayerTouch = strcat(m_strOnPlayerTouch, ",_", strValue);
|
||||
break;
|
||||
default:
|
||||
CBaseTrigger::SpawnKey(strKey, strValue);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void item_suit::item_suit(void)
|
||||
{
|
||||
model = "models/w_suit.mdl";
|
||||
|
@ -81,4 +103,6 @@ void item_suit::item_suit(void)
|
|||
precache_sound("fvox/hev_logon.wav");
|
||||
precache_sound("fvox/bell.wav");
|
||||
CBaseTrigger::CBaseTrigger();
|
||||
|
||||
m_strOnPlayerTouch = CreateOutput(m_strOnPlayerTouch);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue