Server: streamline gamerule progs interface

This commit is contained in:
Marco Cawthorne 2024-11-05 20:35:55 -08:00
parent 967ac0145b
commit 2db52608b1
9 changed files with 145 additions and 351 deletions

View file

@ -90,12 +90,6 @@ public:
virtual int MaxItemPerSlot(int);
/** Overridable: Returns if NSMonster or NSTalkMonster entities can spawn. */
virtual bool MonstersSpawn(void);
/** Overridable: shim to handle application of direct damage. */
nonvirtual void DamageApply(entity,entity,float,int,damageType_t);
/** Checks if an entity can be attacked from a given position. */
nonvirtual bool DamageCheckTrace(entity,vector);
/** Overridable: shim to handle application of indirect radius damage. */
nonvirtual void DamageRadius(vector,entity,float,float,bool,int);
/* end of a game */
/** Called when intermission starts. Will send all current players to the intermission screen. */
@ -147,3 +141,4 @@ private:
NSGameRules g_grMode;
#define CGameRules NSGameRules
#define RULEMAP(x, y, z) x.y = externvalue(x.m_ruleProgs, z); if (!x.y) { x.y = NSGameRules::y; }

View file

@ -18,10 +18,24 @@ var bool autocvar_sv_friendlyFire = false;
var int autocvar_mp_td_dmgToKick = 300i;
var int autocvar_mp_td_dmgToWarn = 200i;
#warning NSGameRule progs need to have their functions cached for speed reasons
void
NSGameRules::NSGameRules(void)
{
forceinfokey(world, "teamplay", "0");
forceinfokey(world, "teams", "");
forceinfokey(world, "teamplay", "");
forceinfokey(world, "coop", "");
/* clean up... */
for (int teamID = 1; teamID < 1000; teamID++) {
forceinfokey(world, sprintf("team_%i", teamID), "");
forceinfokey(world, sprintf("teamscore_%i", teamID), "");
forceinfokey(world, sprintf("teamcolor_%i", teamID), "");
forceinfokey(world, sprintf("teamclosed_%i", teamID), "");
forceinfokey(world, sprintf("teamspawn_%i", teamID), "");
}
forceinfokey(world, sprintf("teamspawn_%d", TEAM_CONNECTING), "");
forceinfokey(world, sprintf("teamspawn_%d", TEAM_UNASSIGNED), "info_player_start");
forceinfokey(world, sprintf("teamspawn_%d", TEAM_SPECTATOR), "info_spectator_start");
@ -55,7 +69,6 @@ NSGameRules::Restore(string strKey, string strValue)
void
NSGameRules::Input(entity eAct, string strInput, string strData)
{
RuleC_CallInput(m_ruleProgs, eAct, strInput, strData);
}
void
@ -69,21 +82,13 @@ NSGameRules::RestoreComplete(void)
void
NSGameRules::InitPostEnts(void)
{
RuleC_CallFunc(m_ruleProgs, world, "CodeCallback_StartGameType");
}
/* logic */
void
NSGameRules::FrameStart(void)
{
//print("StartFrame!\n");
/* hack */
if (time < 2.5f) {
return;
}
RuleC_CallFrame(m_ruleProgs, "CodeCallback_FrameStart");
}
bool
NSGameRules::ConsoleCommand(NSClientPlayer pl, string cmd)
@ -93,13 +98,11 @@ NSGameRules::ConsoleCommand(NSClientPlayer pl, string cmd)
bool
NSGameRules::ClientCommand(NSClient pl, string cmd)
{
return RuleC_CallString(m_ruleProgs, pl, cmd, "CodeCallback_ClientCommand");
}
bool
NSGameRules::ImpulseCommand(NSClient pl, float num)
{
return RuleC_CallFloat(m_ruleProgs, pl, num, "CodeCallback_ImpulseCommand");
}
void
@ -108,14 +111,11 @@ NSGameRules::PlayerConnect(NSClientPlayer pl)
if (Plugin_PlayerConnect(pl) == false) {
bprint(PRINT_HIGH, sprintf("%s^d connected.\n", pl.netname));
}
RuleC_CallFunc(m_ruleProgs, pl, "CodeCallback_PlayerConnect");
}
void
NSGameRules::PlayerDisconnect(NSClientPlayer pl)
{
bprint(PRINT_HIGH, sprintf("%s^d disconnected.\n", pl.netname));
RuleC_CallFunc(m_ruleProgs, pl, "CodeCallback_PlayerDisconnect");
}
void
@ -131,18 +131,11 @@ NSGameRules::PlayerKill(NSClientPlayer pl)
void
NSGameRules::NPCDeath(NSActor npc, NSActor attacker, NSActor inflictor)
{
if (RuleC_CallDamage(m_ruleProgs, npc, attacker, inflictor, "", "CodeCallback_NPCKilled")) {
return;
}
}
void
NSGameRules::PlayerDeath(NSClientPlayer pl, NSActor attacker, NSDict damageDecl)
{
if (RuleC_CallDamage(m_ruleProgs, pl, attacker, attacker, "", "CodeCallback_PlayerKilled")) {
return;
}
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EV_OBITUARY);
WriteString(MSG_MULTICAST, (attacker.netname) ? attacker.netname : attacker.classname);
@ -169,18 +162,12 @@ NSGameRules::PlayerDeath(NSClientPlayer pl, NSActor attacker, NSDict damageDecl)
void
NSGameRules::PlayerPain(NSClientPlayer pl, NSActor attacker, NSDict damageDecl)
{
if (RuleC_CallDamage(m_ruleProgs, pl, attacker, attacker, "", "CodeCallback_PlayerDamage")) {
return;
}
/* fallback code here, or rest implemented by sub-class */
}
void
NSGameRules::PlayerSpawn(NSClientPlayer pl)
{
RuleC_CallFunc(m_ruleProgs, pl, "CodeCallback_PlayerSpawn");
/* implemented by sub-class */
}
void
@ -226,10 +213,6 @@ NSGameRules::SpectatorThink(NSClientSpectator pl)
int
NSGameRules::MaxItemPerSlot(int slot)
{
if (m_ruleProgs) {
return RuleC_CallMaxItemsPerSlot(m_ruleProgs, slot, "CodeCallback_MaxItemPerSlot");
}
return (-1);
}
@ -338,7 +321,7 @@ NSGameRules::MonstersSpawn(void)
bool
NSGameRules::IsTeamplay(void)
{
return (false);
return (serverkeyfloat("teams") > 0);
}
bool
NSGameRules::IsMultiplayer(void)
@ -346,26 +329,6 @@ NSGameRules::IsMultiplayer(void)
return (false);
}
void
NSGameRules::DamageApply(entity t, entity c, float dmg, int w, damageType_t type)
{
NSError("Deprecated!");
}
/* checks if we can hit an entity at 5 of the same spots */
bool
NSGameRules::DamageCheckTrace(entity t, vector vecHitPos)
{
NSError("Deprecated!");
return (false);
}
void
NSGameRules::DamageRadius(vector org, entity attacker, float dmg, float r, bool checkCollision, int w)
{
NSError("Deprecated!");
}
void
NSGameRules::IntermissionEnd(void)
{
@ -393,13 +356,11 @@ NSGameRules::PlayerCanAttack(NSClientPlayer bp)
bool
NSGameRules::PlayerRequestRespawn(NSClientPlayer pl)
{
return RuleC_CallRequestSpawn(m_ruleProgs, pl, "CodeCallback_PlayerRequestRespawn");
}
bool
NSGameRules::PlayerRequestTeam(NSClientPlayer pl, int teamNum)
{
return RuleC_CallRequestTeam(m_ruleProgs, pl, teamNum, "CodeCallback_CallRequestTeam");
}
void
@ -453,6 +414,12 @@ NSGameRules::ChatMessageTeam(NSClient cl, string strMessage)
string
NSGameRules::Title(void)
{
string gameType = cvars.GetString("g_gametype");
if (STRING_SET(gameType)) {
return gameType;
}
return "Default";
}
@ -477,6 +444,24 @@ NSGameRules::InitFromProgs(string pathToProgs)
if (mainFunction) {
externset(newRule.m_ruleProgs, this, "self");
thread(mainFunction())
/* map progs functions to class methods */
RULEMAP(newRule, ClientCommand, "CodeCallback_ClientCommand")
RULEMAP(newRule, ConsoleCommand, "CodeCallback_ConsoleCommand")
RULEMAP(newRule, FrameStart, "CodeCallback_FrameStart")
RULEMAP(newRule, ImpulseCommand, "CodeCallback_ImpulseCommand")
RULEMAP(newRule, InitPostEnts, "CodeCallback_StartGameType")
RULEMAP(newRule, Input, "CodeCallback_Input")
RULEMAP(newRule, NPCDeath, "CodeCallback_NPCKilled")
RULEMAP(newRule, PlayerCanAttack, "CodeCallback_PlayerCanAttack")
RULEMAP(newRule, PlayerConnect, "CodeCallback_PlayerConnect")
RULEMAP(newRule, PlayerDeath, "CodeCallback_PlayerKilled")
RULEMAP(newRule, PlayerDisconnect, "CodeCallback_PlayerDisconnect")
RULEMAP(newRule, PlayerPain, "CodeCallback_PlayerDamage")
RULEMAP(newRule, PlayerRequestRespawn, "CodeCallback_PlayerRequestRespawn")
RULEMAP(newRule, PlayerRequestTeam, "CodeCallback_CallRequestTeam")
RULEMAP(newRule, PlayerSpawn, "CodeCallback_PlayerSpawn")
RULEMAP(newRule, Title, "CodeCallback_Title")
} else {
NSError("%S does not have a main function.", pathToProgs);
}

View file

@ -49,8 +49,17 @@ Cmd_ParseClientCommand(NSClient sender, string cmd, int commandArguments)
PutClientInServer();
break;
case "setpos":
printf("%i %S\n", commandArguments, cmd);
if (cvar("sv_cheats") == 1) {
setorigin(sender, stov(argv(1)));
if (commandArguments == 2) { /* setpos "0 0 0" */
setorigin(sender, stov(argv(1)));
} else if (commandArguments == 3) { /* setpos "0 0 0" "0 0 0" */
setorigin(sender, stov(argv(1)));
} else if (commandArguments == 4) { /* setpos 0 0 0 */
setorigin(sender, [stof(argv(1)), stof(argv(2)), stof(argv(3))]);
} else if (commandArguments == 7) { /* setpos 0 0 0 0 0 0 */
setorigin(sender, [stof(argv(1)), stof(argv(2)), stof(argv(3))]);
}
}
break;
@ -60,8 +69,7 @@ Cmd_ParseClientCommand(NSClient sender, string cmd, int commandArguments)
float timeleft;
timeleft = cvar("timelimit") - (time / 60);
timestring = Util_TimeToString(timeleft);
msg = sprintf("we have %s minutes remaining", timestring);
bprint(PRINT_CHAT, msg);
bprint(PRINT_CHAT, sprintf("we have %s minutes remaining", timestring));
break;
case "listInventory":
NSActor_ListInventory((NSActor)self);

View file

@ -19,17 +19,3 @@ void MapC_Init(void);
void MapC_CallMainFunction(void);
void MapC_CallNamedFunction(entity, string);
bool RuleC_CallFunc(float, entity, string);
bool RuleC_CallFrame(float, string);
bool RuleC_CallDamage(float, entity, entity, entity, string, string);
bool RuleC_CallRequestSpawn(float, entity, string);
bool RuleC_CallRequestTeam(float, entity, int, string);
bool RuleC_CallString(float, entity, string, string);
bool RuleC_CallFloat(float, entity, float, string);
int RuleC_CallMaxItemsPerSlot(float, int, string);
void RuleC_CallInput(float, entity, string, string);

View file

@ -73,185 +73,3 @@ MapC_CallNamedFunction(entity functionActivator, string targetFunction)
NSError("%s does not have a function %s.", mapname, targetFunction);
}
}
/* Gamerule specific Scripting, nicknamed 'RuleC'. */
bool
RuleC_CallFunc(float progsNum, entity pl, string funcName)
{
if (progsNum) {
void(void) mainFunction;
mainFunction = externvalue(progsNum, funcName);
if (mainFunction) {
entity oldSelf = self;
//externset(progsNum, pl, "self");
self = pl;
mainFunction();
self = oldSelf;
return (true);
}
}
return (false);
}
bool
RuleC_CallFrame(float progsNum, string funcName)
{
if (progsNum) {
void(void) mainFunction;
mainFunction = externvalue(progsNum, funcName);
if (mainFunction) {
entity oldSelf = self;
externset(progsNum, frametime, "frametime");
self = world;
mainFunction();
self = oldSelf;
return (true);
}
}
return (false);
}
bool
RuleC_CallDamage(float progsNum, entity target, entity inflictor, entity attacker, string weapon, string funcName)
{
if (progsNum) {
void(entity inflictor, entity attacker, string weapon) mainFunction;
mainFunction = externvalue(progsNum, funcName);
if (mainFunction) {
entity oldSelf = self;
externset(progsNum, target, "self");
self = target;
mainFunction(inflictor, attacker, weapon);
self = oldSelf;
forceinfokey(target, "*deaths", ftos(target.deaths));
return (true);
}
}
return (false);
}
bool
RuleC_CallRequestSpawn(float progsNum, entity pl, string funcName)
{
bool returnValue = false;
if (progsNum) {
bool(void) mainFunction;
mainFunction = externvalue(progsNum, funcName);
if (mainFunction) {
entity oldSelf = self;
externset(progsNum, pl, "self");
self = pl;
returnValue = mainFunction();
self = oldSelf;
return (returnValue);
}
}
return (returnValue);
}
bool
RuleC_CallRequestTeam(float progsNum, entity pl, int teamNum, string funcName)
{
bool returnValue = false;
if (progsNum) {
bool(int) mainFunction;
mainFunction = externvalue(progsNum, funcName);
if (mainFunction) {
entity oldSelf = self;
externset(progsNum, pl, "self");
self = pl;
returnValue = mainFunction(teamNum);
self = oldSelf;
return (returnValue);
}
}
return (returnValue);
}
bool
RuleC_CallString(float progsNum, entity pl, string targetString, string funcName)
{
bool returnValue = false;
if (progsNum) {
bool(string) mainFunction;
mainFunction = externvalue(progsNum, funcName);
if (mainFunction) {
entity oldSelf = self;
externset(progsNum, pl, "self");
self = pl;
returnValue = mainFunction(targetString);
self = oldSelf;
return (returnValue);
}
}
return (returnValue);
}
bool
RuleC_CallFloat(float progsNum, entity pl, float targetFloat, string funcName)
{
bool returnValue = false;
if (progsNum) {
bool(float) mainFunction;
mainFunction = externvalue(progsNum, funcName);
if (mainFunction) {
entity oldSelf = self;
externset(progsNum, pl, "self");
self = pl;
returnValue = mainFunction(targetFloat);
self = oldSelf;
return (returnValue);
}
}
return (returnValue);
}
int
RuleC_CallMaxItemsPerSlot(float progsNum, int targetFloat, string funcName)
{
int returnValue = -1i;
if (progsNum) {
int(int) mainFunction;
mainFunction = externvalue(progsNum, funcName);
if (mainFunction) {
returnValue = mainFunction(targetFloat);
return (returnValue);
}
}
return (returnValue);
}
void
RuleC_CallInput(float progsNum, entity activator, string inputName, string inputData)
{
if (progsNum) {
void(entity, string, string) mainFunction;
mainFunction = externvalue(progsNum, "CodeCallback_Input");
if (mainFunction) {
mainFunction(activator, inputName, inputData);
}
}
}

View file

@ -1747,6 +1747,12 @@ NSClientPlayer::Damage(entity inflictor, entity attacker, NSDict damageDecl, flo
damageDecl.AddKey("location", vtos(hitLocation));
/* apply knockback, but only on death */
float knockBack = damageDecl.GetFloat("knockback");
if (knockBack >= 0) {
AddVelocity(dmgDir * knockBack);
}
/* they died */
if (GetHealth() <= 0) {
g_grMode.PlayerDeath(this, (NSActor)attacker, damageDecl);

View file

@ -89,11 +89,12 @@ private:
/** Will transport an entity from its position to the exit position. */
nonvirtual void TransportEntity(NSEntity);
#ifdef CLIENT
vector m_vecTargetPos;
vector m_vecTargetN;
vector m_vecTargetS;
vector m_vecTargetT;
#ifdef CLIENT
float m_flSize;
#endif
@ -117,4 +118,4 @@ private:
.float portalnum;
.float impulse; //used as the radius for the solid_portal csg subtraction
.bool isPortal;
.bool isPortal;

View file

@ -32,13 +32,10 @@ NSPortal::NSPortal(void)
m_brushNum = -1;
m_bEnabled = false;
isPortal = true;
#ifdef CLIENT
m_vecTargetPos = g_vec_null;
m_vecTargetN = g_vec_null;
m_vecTargetS = g_vec_null;
m_vecTargetT = g_vec_null;
#endif
#ifdef SERVER
@ -150,15 +147,15 @@ NSPortal::PortalClose(void)
/* invalidate the other portal's reference to this one, only
if we're still actively linked. */
if (m_ePortalTarget && m_ePortalTarget.m_ePortalTarget == this) {
m_ePortalTarget.m_bEnabled = false;
m_ePortalTarget.m_bEnabled = false;
m_ePortalTarget.m_ePortalTarget = __NULL__;
m_ePortalTarget._PortalUpdated();
m_ePortalTarget._PortalUpdated();
}
/* now kill our own reference */
m_ePortalTarget = __NULL__;
m_bEnabled = false;
_PortalUpdated();
_PortalUpdated();
}
bool
@ -167,16 +164,17 @@ NSPortal::PortalLinkTo(NSPortal target, bool openPortal)
m_ePortalTarget = target;
m_bEnabled = openPortal;
SendFlags = -1;
_PortalUpdated();
if (m_ePortalTarget) {
m_ePortalTarget.m_ePortalTarget = this;
m_ePortalTarget.m_bEnabled = openPortal;
m_ePortalTarget.SendFlags = -1;
m_ePortalTarget._PortalUpdated();
}
SendFlags = -1;
_PortalUpdated();
if (m_ePortalTarget)
{
m_ePortalTarget.m_ePortalTarget = this;
m_ePortalTarget.m_bEnabled = openPortal;
m_ePortalTarget.SendFlags = -1;
m_ePortalTarget._PortalUpdated();
}
return target ? true : false;
}
@ -208,22 +206,24 @@ void
NSPortal::_PortalUpdated(void)
{
/* the displayed surface must be in a known position.
we're not going to compensate for the model here, because I'm too lazy. */
we're not going to compensate for the model here, because I'm too lazy.
*/
vector newAngles = angles;
//newAngles[0] * -1;
makevectors(newAngles);
makevectors(newAngles);
m_vecPortalN = v_forward;
m_vecPortalS = -v_right;
m_vecPortalT = v_up;
m_vecPortalPos = origin;
/* expand the size of the object along the plane, and set up a portal region. */
movetype = MOVETYPE_NONE;
m_vecPortalN = v_forward;
m_vecPortalS = -v_right;
m_vecPortalT = v_up;
m_vecPortalPos = origin;
/* expand the size of the object along the plane, and set up a portal region.
*/
movetype = MOVETYPE_NONE;
if (m_bEnabled == true) {
solid = SOLID_PORTAL;
setmodel(this, modelnameforindex(m_flPortalModel));
setmodel(this, modelnameforindex(m_flPortalModel));
if (m_bWasEnabled == false) {
m_bWasEnabled = true;
#ifdef SERVER
@ -244,81 +244,75 @@ NSPortal::_PortalUpdated(void)
//modelindex = 0;
}
/* determine size of major axis */
float portalSize = max(size[0], size[1], size[2]);
impulse = portalSize; /* let the engine know how wide the portal should be */
/* make sure the abs size contains the entire portal. */
portalSize = sqrt(portalSize * portalSize * 2);
mins -= portalSize * [1, 1, 1];
maxs += portalSize * [1, 1, 1];
setsize(this, mins, maxs);
/* determine size of major axis
*/
float portalSize = max(size[0], size[1], size[2]);
impulse = portalSize; /* let the engine know how wide the portal should be
*/
/* make sure the abs size contains the entire portal.
*/
portalSize = sqrt(portalSize * portalSize * 2);
mins -= portalSize * [1, 1, 1];
maxs += portalSize * [1, 1, 1];
setsize(this, mins, maxs);
}
vector
NSPortal::_DirectionTransform(vector v)
{
/* FIXME: this should include .angles stuff */
vector tmp, r;
tmp[0] = v * m_vecPortalN;
tmp[1] = v * m_vecPortalS;
tmp[2] = v * m_vecPortalT;
{
/* FIXME: this should include .angles stuff
*/
vector tmp, r;
tmp[0] = v * m_vecPortalN;
tmp[1] = v * m_vecPortalS;
tmp[2] = v * m_vecPortalT;
r = [0, 0, 0];
if (!m_ePortalTarget) {
#ifdef CSQC
r += tmp[2] * m_vecTargetT;
r -= tmp[1] * m_vecTargetS;
r -= tmp[0] * m_vecTargetN;
#else
r += tmp[2] * this.m_vecPortalT;
r -= tmp[1] * this.m_vecPortalS;
r -= tmp[0] * this.m_vecPortalN;
#endif
} else {
r += tmp[2] * m_ePortalTarget.m_vecPortalT;
r -= tmp[1] * m_ePortalTarget.m_vecPortalS;
r -= tmp[0] * m_ePortalTarget.m_vecPortalN;
}
if (!m_ePortalTarget) {
r += tmp[2] * m_vecTargetT;
r -= tmp[1] * m_vecTargetS;
r -= tmp[0] * m_vecTargetN;
} else {
r += tmp[2] * m_ePortalTarget.m_vecPortalT;
r -= tmp[1] * m_ePortalTarget.m_vecPortalS;
r -= tmp[0] * m_ePortalTarget.m_vecPortalN;
}
return r;
return r;
}
vector
NSPortal::_OriginTransform(vector p)
{
if (!m_ePortalTarget) {
#ifdef CSQC
return m_vecTargetPos - _DirectionTransform(m_vecPortalPos - p);
#else
return this.m_vecPortalPos - _DirectionTransform(m_vecPortalPos - p);
#endif
}
NSPortal::_OriginTransform(vector p)
{
if (!m_ePortalTarget) {
return m_vecPortalPos - _DirectionTransform(m_vecPortalPos - p);
}
return m_ePortalTarget.m_vecPortalPos - _DirectionTransform(m_vecPortalPos - p);
return m_ePortalTarget.m_vecPortalPos - _DirectionTransform(m_vecPortalPos - p);
}
// need to generate forward/right/up vectors
// return value is the new view origin.
// trace_end_pos needs to contain the pvs origin.
// need to generate forward/right/up vectors
// return value is the new view origin.
// trace_end_pos needs to contain the pvs origin.
vector
NSPortal::camera_transform(vector originalOrg, vector originalAngles)
{
vector newCameraPos;
newCameraPos = _OriginTransform(originalOrg);
v_forward = _DirectionTransform(v_forward);
v_right = _DirectionTransform(v_right);
v_up = _DirectionTransform(v_up);
//trace from the center of the target to the view, to set trace_endpos for the pvs origin
if (m_ePortalTarget)
traceline(m_ePortalTarget.m_vecPortalPos, newCameraPos, MOVE_NOMONSTERS, this);
else
trace_endpos = this.m_vecPortalPos;
{
vector newCameraPos;
return newCameraPos;
newCameraPos = _OriginTransform(originalOrg);
v_forward = _DirectionTransform(v_forward);
v_right = _DirectionTransform(v_right);
v_up = _DirectionTransform(v_up);
//trace from the center of the target to the view, to set trace_endpos for the pvs origin
if (m_ePortalTarget)
traceline(m_ePortalTarget.m_vecPortalPos, newCameraPos, MOVE_NOMONSTERS, this);
else
trace_endpos = this.m_vecPortalPos;
return newCameraPos;
}
/* because when using custom player physics, the engine will not do us any favors

View file

@ -19,9 +19,10 @@ NSSurfacePropEntity::NSSurfacePropEntity(void)
{
m_flBurnNext = 0.0f;
#ifdef SERVER
max_health = 100;
max_armor = 100;
m_iPropData = -1i;
m_iMaterial = -1i;
max_health = 100;
m_strOnBreak = __NULL__;
m_eBurner= __NULL__;
m_iBurnWeapon = 0i;
@ -255,7 +256,7 @@ NSSurfacePropEntity::Damage(entity inflictor, entity attacker, NSDict damageDecl
health = rint(health - damagePoints);
if (health <= 0) {
/* apply knockback */
/* apply knockback, but only on death */
float knockBack = damageDecl.GetFloat("knockback");
if (knockBack >= 0) {
AddVelocity(dmgDir * knockBack);