Move gamerules over for override

This commit is contained in:
Marco Cawthorne 2023-09-25 16:14:48 -07:00
parent 97c056ae90
commit 753126c5c7
Signed by: eukara
GPG key ID: CE2032F0A2882A22
5 changed files with 480 additions and 108 deletions

View file

@ -1,106 +0,0 @@
/*
* Copyright (c) 2023 Marco Cawthorne <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.
*/
class OP4CTFItem:NSRenderableEntity
{
public:
void OP4CTFItem(void);
virtual void Respawn(void);
virtual void Touch(entity);
nonvirtual bool CanPlayerGrabPowerup(entity);
virtual void SpawnKey(string, string);
private:
int m_iItemID;
float m_iTeamID;
string m_strScoreIcon;
vector m_vecScoreColor;
};
void
OP4CTFItem::OP4CTFItem(void)
{
m_iItemID = 0i;
m_strScoreIcon = __NULL__;
m_iTeamID = 0;
m_vecScoreColor = [1,1,1];
}
void
OP4CTFItem::Respawn(void)
{
SetSolid(SOLID_TRIGGER);
SetMovetype(MOVETYPE_NONE);
SetOrigin(GetSpawnOrigin());
SetModel(GetSpawnModel());
SetSize([-16, -16, 0], [16, 16, 72]);
DropToFloor();
}
void
OP4CTFItem::SpawnKey(string strKey, string strValue)
{
switch (strKey) {
case "goal_no":
m_iTeamID = ReadFloat(strValue);
break;
default:
super::SpawnKey(strKey, strValue);
}
}
void
OP4CTFItem::Touch(entity toucherEntity)
{
player pl = (player)toucherEntity;
if (!m_iItemID)
return;
if (!(toucherEntity.flags & FL_CLIENT))
return;
if (CanPlayerGrabPowerup(toucherEntity) == false)
return;
pl.g_items |= m_iItemID; /* add to inventory */
forceinfokey(pl, "*icon2", m_strScoreIcon);
forceinfokey(pl, "*icon2_r", ftos(m_vecScoreColor[0]));
forceinfokey(pl, "*icon2_g", ftos(m_vecScoreColor[1]));
forceinfokey(pl, "*icon2_b", ftos(m_vecScoreColor[2]));
Destroy();
}
bool
OP4CTFItem::CanPlayerGrabPowerup(entity playerEntity)
{
player pl = (player)playerEntity;
if (pl.g_items & ITEM_CTF_JUMPPACK)
return false;
if (pl.g_items & ITEM_CTF_SHIELD)
return false;
if (pl.g_items & ITEM_CTF_HEALTH)
return false;
if (pl.g_items & ITEM_CTF_DEATH)
return false;
if (pl.g_items & ITEM_CTF_BACKPACK)
return false;
return true;
}

View file

@ -0,0 +1,299 @@
/*
* Copyright (c) 2016-2020 Marco Cawthorne <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.
*/
const string mp_teamlist_fallback = "robo;hgrunt";
var string autocvar_mp_teamlist = mp_teamlist_fallback;
bool
HLMultiplayerRules::IsMultiplayer(void)
{
return true;
}
bool
HLMultiplayerRules::PlayerRequestRespawn(NSClientPlayer bp)
{
if (bp.TimeSinceDeath() > 0.5f) {
bp.ScheduleThink(PutClientInServer, 0.0f);
return true;
}
return false;
}
bool
HLMultiplayerRules::IsTeamplay(void)
{
return cvar("mp_teamplay") == 1 ? true : false;
}
void
HLMultiplayerRules::InitPostEnts(void)
{
MOTD_LoadDefault();
forceinfokey(world, "scorepoints", "0");
if (IsTeamplay() == true) {
int c;
/* get the segments from our cvar */
m_strTeamList = autocvar_mp_teamlist;
c = tokenizebyseparator(m_strTeamList, ";");
/* if we've got less than 2 teams, use the fallback... */
if (c < 2) {
m_strTeamList = mp_teamlist_fallback;
c = tokenizebyseparator(m_strTeamList, ";");
}
forceinfokey(world, "teams", itos(c));
/* initialize all dem teams */
for (int i = 0; i < c; i++) {
forceinfokey(world, sprintf("team_%i", i+1i), argv(i));
forceinfokey(world, sprintf("teamscore_%i", i+1i), "0");
}
} else {
forceinfokey(world, "teams", "0");
}
}
void
HLMultiplayerRules::FrameStart(void)
{
if (cvar("timelimit"))
if (time >= (cvar("timelimit") * 60)) {
IntermissionStart();
}
IntermissionCycle();
}
void
HLMultiplayerRules::CheckRules(void)
{
/* last person who killed somebody has hit the limit */
if (cvar("fraglimit"))
if (g_dmg_eAttacker.frags >= cvar("fraglimit"))
IntermissionStart();
}
void
HLMultiplayerRules::PlayerDeath(NSClientPlayer pl)
{
/* obituary networking */
WriteByte(MSG_MULTICAST, SVC_CGAMEPACKET);
WriteByte(MSG_MULTICAST, EV_OBITUARY);
WriteString(MSG_MULTICAST, (g_dmg_eAttacker.netname) ? g_dmg_eAttacker.netname : g_dmg_eAttacker.classname);
WriteString(MSG_MULTICAST, pl.netname);
WriteByte(MSG_MULTICAST, g_dmg_iWeapon);
WriteByte(MSG_MULTICAST, 0);
msg_entity = world;
multicast([0,0,0], MULTICAST_ALL);
Plugin_PlayerObituary(g_dmg_eAttacker, g_dmg_eTarget, g_dmg_iWeapon, g_dmg_iHitBody, g_dmg_iDamage);
/* death-counter */
pl.deaths++;
pl.SetInfoKey("*deaths", ftos(pl.deaths));
/* update score-counter */
if (pl.flags & FL_CLIENT || pl.flags & FL_MONSTER)
if (g_dmg_eAttacker.flags & FL_CLIENT) {
if (pl == g_dmg_eAttacker)
g_dmg_eAttacker.frags--;
else
g_dmg_eAttacker.frags++;
}
#ifdef VALVE
/* explode all satchels */
s_satchel_detonate((entity)pl);
/* drop their posessions into a weaponbox item */
weaponbox_spawn((player)pl);
#endif
/* either gib, or make a corpse */
if (pl.health < -50) {
vector gibDir = vectoangles(pl.origin - g_dmg_eAttacker.origin);
float gibStrength = g_dmg_iDamage * 2.0f;
BreakModel_Entity(pl, gibDir, gibStrength);
} else {
FX_Corpse_Spawn((player)pl, ANIM_DIESIMPLE);
}
/* now let's make the real client invisible */
pl.Death();
pl.SetTakedamage(DAMAGE_NO);
pl.gflags &= ~GF_FLASHLIGHT;
pl.gflags &= ~GF_EGONBEAM;
Sound_Play(pl, CHAN_AUTO, "player.die");
/* force respawn */
pl.ScheduleThink(PutClientInServer, 4.0f);
/* have we gone over the fraglimit? */
CheckRules();
}
void
HLMultiplayerRules::PlayerSpawn(NSClientPlayer pp)
{
player pl = (player)pp;
string playerModel;
/* this is where the mods want to deviate */
entity spot;
pl.classname = "player";
pl.SetMaxHealth(100);
pl.SetHealth(100);
pl.SetTakedamage(DAMAGE_YES);
pl.SetSolid(SOLID_SLIDEBOX);
pl.SetMovetype(MOVETYPE_WALK);
pl.AddFlags(FL_CLIENT);
pl.viewzoom = 1.0;
/* player model selection */
if (IsTeamplay() == true) {
int teamCount = tokenizebyseparator(m_strTeamList, ";");
int playerTeam = (int)pl.GetTeam();
/* not part of a team? pick one of the ones we have */
/* TODO: this should sort us into the lowest team */
if (playerTeam == 0) {
playerTeam = 1i + (int)floor(random(0, (float)teamCount)); /* teams start at 1 after all */
pl.SetTeam(playerTeam);
}
/* assign our player model */
playerModel = sprintf("models/player/%s/%s.mdl", argv(playerTeam - 1i), argv(playerTeam - 1i));
} else {
/* interpret the 'model' InfoKey */
playerModel = pl.GetInfoKey("model");
if (playerModel) {
playerModel = sprintf("models/player/%s/%s.mdl", playerModel, playerModel);
}
}
/* fallback is always models/player.mdl for Half-Life */
if not (whichpack(playerModel)) {
playerModel = "models/player.mdl";
}
pl.SetModel(playerModel);
pl.SetSize(VEC_HULL_MIN, VEC_HULL_MAX);
pl.ClearVelocity();
pl.gravity = __NULL__;
pl.SetFrame(1);
pl.SendFlags = UPDATE_ALL;
pl.SetInfoKey("*spec", "0");
pl.SetInfoKey("*dead", "0");
pl.SetInfoKey("*deaths", ftos(pl.deaths));
pl.SetPropData("actor_human");
pl.SetCanBleed(true);
LevelNewParms();
LevelDecodeParms(pl);
#if defined (VALVE) || defined (GEARBOX)
pl.g_items = ITEM_CROWBAR | ITEM_GLOCK | ITEM_SUIT;
pl.activeweapon = WEAPON_GLOCK;
pl.glock_mag = 18;
pl.ammo_9mm = 44;
#elif defined (HL2)
pl.g_items = ITEM_CROWBAR | ITEM_PISTOL | ITEM_GRAVITYGUN | ITEM_SUIT;
pl.activeweapon = WEAPON_GRAVITYGUN;
pl.glock_mag = 18;
pl.ammo_9mm = 44;
#endif
spot = Spawn_SelectRandom("info_player_deathmatch");
pl.Transport(spot.origin, spot.angles);
Weapons_RefreshAmmo(pl);
Client_FixAngle(pl, pl.angles);
}
bool
HLMultiplayerRules::ConsoleCommand(NSClientPlayer pp, string cmd)
{
tokenize(cmd);
switch (argv(0)) {
case "bot_add":
bot pete = (bot)Bot_AddQuick();
Bot_RandomColormap(pete);
searchhandle pm = search_begin("models/player/*/*.mdl", TRUE, TRUE);
int r = floor(random(0, search_getsize(pm)));
string mdl = substring(search_getfilename(pm, r), 0, -5);
tokenizebyseparator(mdl, "/");
pete.SetInfoKey("model", argv(2));
search_end(pm);
break;
case "jumptest":
makevectors(pp.v_angle);
traceline(pp.origin + pp.view_ofs, pp.origin + pp.view_ofs + v_forward * 1024, FALSE, pp);
pp.velocity = Route_GetJumpVelocity(pp.origin, trace_endpos, pp.gravity);
break;
default:
return (false);
}
return (true);
}
bool
HLMultiplayerRules::MonstersSpawn(void)
{
return (autocvar(mp_allowmonsters, 0)) ? true : false;
}
void
HLMultiplayerRules::HLMultiplayerRules(void)
{
/* these lines do nothing but tell the server to register those cvars */
autocvar(timelimit, 15, "Timelimit for multiplayer rounds");
autocvar(fraglimit, 15, "Points limit for multiplayer rounds");
}
void
CSEv_HLDM_Chooseteam_s(string teamName)
{
HLGameRules rules = (HLGameRules)g_grMode;
player pl = (player)self;
if (!teamName)
return;
if (rules.IsMultiplayer() == false)
return;
if (rules.IsTeamplay() == false)
return;
if (pl.IsDead() == true)
return;
HLMultiplayerRules mprules = (HLMultiplayerRules)rules;
int c = tokenizebyseparator(mprules.m_strTeamList, ";");
for (int i = 0; i < c; i++) {
if (argv(i) == teamName) {
pl.SetTeam((float)i + 1);
Damage_Apply(pl, pl, 100, 0, DMG_SKIP_ARMOR);
return;
}
}
}

View file

@ -0,0 +1,165 @@
/*
* Copyright (c) 2016-2020 Marco Cawthorne <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.
*/
bool
HLSingleplayerRules::IsMultiplayer(void)
{
return false;
}
void
HLSingleplayerRules::PlayerDeath(NSClientPlayer pl)
{
pl.SetMovetype(MOVETYPE_NONE);
pl.SetSolid(SOLID_NOT);
pl.SetTakedamage(DAMAGE_NO);
pl.SetHealth(0);
pl.StartSoundDef("player.die", CHAN_AUTO, true);
pl.gflags &= ~GF_FLASHLIGHT;
pl.armor = pl.activeweapon = pl.g_items = pl.weapon = 0;
if (cvar("coop") == 1) {
pl.ScheduleThink(PutClientInServer, 4.0f);
}
/* so much damage we're gonna gib */
if (pl.GetHealth() < -50) {
//pl.Gib();
//FX_GibHuman(pl.origin, vectoangles(pl.origin - g_dmg_eAttacker.origin), g_dmg_iDamage * 2.0f);
}
/* Let's handle corpses on the clientside */
entity corpse = spawn();
setorigin(corpse, pl.origin + [0,0,32]);
setmodel(corpse, pl.model);
setsize(corpse, VEC_HULL_MIN, VEC_HULL_MAX);
corpse.movetype = MOVETYPE_TOSS;
corpse.solid = SOLID_TRIGGER;
corpse.modelindex = pl.modelindex;
corpse.frame = ANIM_DIESIMPLE;
corpse.angles = pl.angles;
corpse.velocity = pl.velocity;
}
void
HLSingleplayerRules::PlayerSpawn(NSClientPlayer pl)
{
string playerModel = "models/player.mdl";
pl.classname = "player";
pl.SetHealth(100);
pl.SetMaxHealth(100);
pl.SetTakedamage(DAMAGE_YES);
pl.SetSolid(SOLID_SLIDEBOX);
pl.SetMovetype(MOVETYPE_WALK);
pl.AddFlags(FL_CLIENT);
pl.viewzoom = 1.0;
/* if in cooperative mode, we want to respect the player model */
if (cvar("coop") == 1) {
string testModel = infokey(pl, "model");
if (testModel) {
testModel = sprintf("models/player/%s/%s.mdl", testModel, testModel);
if (whichpack(testModel)) {
playerModel = testModel;
}
}
}
pl.SetModel(playerModel);
pl.SetSize(VEC_HULL_MIN, VEC_HULL_MAX);
pl.ClearVelocity();
pl.SetInfoKey("*spec", "0");
pl.SetInfoKey("*deaths", ftos(pl.deaths));
pl.SetCanBleed(true);
if (startspot != "") {
LevelDecodeParms(pl);
pl.SetOrigin(Landmark_GetSpot());
} else {
entity spawnPoint;
LevelNewParms();
spawnPoint = find(world, ::classname, "info_player_start");
pl.Transport(spawnPoint.origin, spawnPoint.angles);
}
Weapons_RefreshAmmo(pl);
Client_FixAngle(pl, pl.angles);
}
bool
HLSingleplayerRules::ImpulseCommand(NSClient bp, float num)
{
switch (num) {
case 101:
player pl = (player)bp;
pl.SetHealth(100);
pl.SetMaxHealth(100);
pl.SetArmor(100);
pl.g_items |= ITEM_SUIT;
#ifdef HL2
Weapons_AddItem(pl, WEAPON_CROWBAR, -1);
Weapons_AddItem(pl, WEAPON_357, -1);
Weapons_AddItem(pl, WEAPON_AR2, -1);
Weapons_AddItem(pl, WEAPON_BUGBAIT, -1);
Weapons_AddItem(pl, WEAPON_CROSSBOW, -1);
Weapons_AddItem(pl, WEAPON_CROWBAR, -1);
Weapons_AddItem(pl, WEAPON_FRAG, -1);
Weapons_AddItem(pl, WEAPON_GRAVITYGUN, -1);
Weapons_AddItem(pl, WEAPON_PISTOL, -1);
Weapons_AddItem(pl, WEAPON_RPG, -1);
Weapons_AddItem(pl, WEAPON_SHOTGUN, -1);
Weapons_AddItem(pl, WEAPON_SMG1, -1);
Weapons_AddItem(pl, WEAPON_STUNSTICK, -1);
Weapons_AddItem(pl, WEAPON_SLAM, -1);
pl.ammo_m203_grenade = 10;
#else
Weapons_AddItem(pl, WEAPON_CROWBAR, -1);
Weapons_AddItem(pl, WEAPON_GLOCK, -1);
Weapons_AddItem(pl, WEAPON_PYTHON, -1);
Weapons_AddItem(pl, WEAPON_MP5, -1);
Weapons_AddItem(pl, WEAPON_SHOTGUN, -1);
Weapons_AddItem(pl, WEAPON_CROSSBOW, -1);
Weapons_AddItem(pl, WEAPON_RPG, -1);
Weapons_AddItem(pl, WEAPON_GAUSS, -1);
Weapons_AddItem(pl, WEAPON_EGON, -1);
Weapons_AddItem(pl, WEAPON_HORNETGUN, -1);
Weapons_AddItem(pl, WEAPON_HANDGRENADE, -1);
Weapons_AddItem(pl, WEAPON_SATCHEL, -1);
Weapons_AddItem(pl, WEAPON_TRIPMINE, -1);
Weapons_AddItem(pl, WEAPON_SNARK, -1);
pl.ammo_m203_grenade = 10;
#ifdef GEARBOX
Weapons_AddItem(pl, WEAPON_PIPEWRENCH, -1);
Weapons_AddItem(pl, WEAPON_KNIFE, -1);
Weapons_AddItem(pl, WEAPON_GRAPPLE, -1);
Weapons_AddItem(pl, WEAPON_EAGLE, -1);
Weapons_AddItem(pl, WEAPON_PENGUIN, -1);
Weapons_AddItem(pl, WEAPON_M249, -1);
Weapons_AddItem(pl, WEAPON_DISPLACER, -1);
Weapons_AddItem(pl, WEAPON_SNIPERRIFLE, -1);
Weapons_AddItem(pl, WEAPON_SPORELAUNCHER, -1);
Weapons_AddItem(pl, WEAPON_SHOCKRIFLE, -1);
#endif
#endif
break;
default:
return super::ImpulseCommand(bp, num);
}
return true;
}

View file

@ -38,8 +38,8 @@ defs.h
../../../src/botlib/include.src
gamerules.qc
../../../valve/src/server/gamerules_singleplayer.qc
../../../valve/src/server/gamerules_multiplayer.qc
gamerules_singleplayer.qc
gamerules_multiplayer.qc
server.qc
../../../valve/src/server/damage.qc
../../../valve/src/server/flashlight.qc

View file

@ -0,0 +1,14 @@
r_part beam
{
texture "particles/fteparticlefont.tga"
tcoords 97 97 191 191 256
scale 1
scaledelta 0.5
alpha 0.4
step 4
randomvel 0
rgb 255 0 0
rgbdelta -150 0 0
type beam
blend add
}