From fbb2df4b6e1bea4ab21c93a79d4de59e861672b2 Mon Sep 17 00:00:00 2001 From: Marco Cawthorne Date: Thu, 14 Jul 2022 17:58:08 -0700 Subject: [PATCH] Some more work done on the gamemodes. Team modes + standard hunt is now implemented but not quite tested. Still needs 'changeteam' cmd etc. --- src/client/cmds.qc | 31 ++++++++ src/client/draw.qc | 63 ++++++++++++++++ src/client/progs.src | 4 +- src/server/gamerules.h | 29 +++++--- src/server/gamerules.qc | 123 +++++++++++++++++++++++++------- src/server/gamerules_hunt.qc | 28 ++++++++ src/server/monster_scientist.qc | 27 +++++-- src/server/server.qc | 2 + 8 files changed, 265 insertions(+), 42 deletions(-) create mode 100644 src/client/cmds.qc create mode 100644 src/client/draw.qc diff --git a/src/client/cmds.qc b/src/client/cmds.qc new file mode 100644 index 0000000..ae973d7 --- /dev/null +++ b/src/client/cmds.qc @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2016-2020 Marco Cawthorne + * + * 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. + */ + +int +ClientGame_ConsoleCommand(void) +{ + switch(argv(0)) { + case "+sciboard": + g_sciboard = true; + break; + case "-sciboard": + g_sciboard = false; + break; + default: + return (0); + } + return (1); +} diff --git a/src/client/draw.qc b/src/client/draw.qc new file mode 100644 index 0000000..3c62b97 --- /dev/null +++ b/src/client/draw.qc @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2016-2022 Vera Visions LLC. + * + * 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. +*/ + +var bool g_sciboard = false; + +void +ClientGame_PreDraw(void) +{ + +} + +void +SH_DrawSciBoard(void) +{ + string line; + vector pos; + + line = "^xFA0Scientist round score info:"; + pos = (video_res / 2); + pos[0] -= (Font_StringWidth(line, FALSE, FONT_CON) / 2); + pos[1] -= 64; + Font_DrawText(pos, line, FONT_CON); + + + line = sprintf("^xFA0Team Red: %d kills", serverkeyfloat("teamkills_1")); + pos = (video_res / 2); + pos[0] -= (Font_StringWidth(line, FALSE, FONT_CON) / 2); + pos[1] -= 36; + Font_DrawText(pos, line, FONT_CON); + + + line = sprintf("^xFA0Team Blue: %d kills", serverkeyfloat("teamkills_2")); + pos = (video_res / 2); + pos[0] -= (Font_StringWidth(line, FALSE, FONT_CON) / 2); + pos[1] -= 24; + Font_DrawText(pos, line, FONT_CON); + + + line = sprintf("^xFA0Scientists left: %d", serverkeyfloat("sci_count")); + pos = (video_res / 2); + pos[0] -= (Font_StringWidth(line, FALSE, FONT_CON) / 2); + Font_DrawText(pos, line, FONT_CON); +} + +void +ClientGame_PostDraw(void) +{ + if (g_sciboard) + SH_DrawSciBoard(); +} diff --git a/src/client/progs.src b/src/client/progs.src index 71c1b02..4849672 100644 --- a/src/client/progs.src +++ b/src/client/progs.src @@ -19,12 +19,12 @@ ../shared/include.src ../../../valve/src/client/damage.qc -../../../base/src/client/draw.qc +draw.qc ../../../valve/src/client/init.qc ../../../valve/src/client/flashlight.qc ../../../valve/src/client/player.qc ../../../valve/src/client/entities.qc -../../../valve/src/client/cmds.qc +cmds.qc ../../../valve/src/client/game_event.qc ../../../valve/src/client/camera.qc ../../../valve/src/client/viewmodel.qc diff --git a/src/server/gamerules.h b/src/server/gamerules.h index a3eda69..5ecfb91 100644 --- a/src/server/gamerules.h +++ b/src/server/gamerules.h @@ -18,32 +18,45 @@ class HLGameRules:CGameRules { + int m_iScientistsAlive; + float m_flRestockTimer; float m_flBreakRespawnTimer; /* client */ virtual void(NSClientPlayer) PlayerSpawn; - virtual void(NSClientPlayer) PlayerConnect; - virtual void(NSClientPlayer) PlayerDisconnect; - virtual void(NSClientPlayer) PlayerKill; virtual void(NSClientPlayer) PlayerDeath; virtual void(NSClientPlayer) PlayerPostFrame; virtual void(NSClientPlayer, entity) ScientistKill; + virtual void(void) RegisterSciDeath; virtual void(NSClientPlayer) LevelDecodeParms; virtual void(NSClientPlayer) LevelChangeParms; virtual void(void) LevelNewParms; virtual void(void) FrameStart; virtual bool(void) IsMultiplayer; + virtual void(void) RestartRound; + + virtual void(void) CountScientists; void(void) HLGameRules; }; class SHTeamRules:HLGameRules { + int m_iKillsTeam1; + int m_iKillsTeam2; + + int m_iScoreTeam1; + int m_iScoreTeam2; + void(void) SHTeamRules; + virtual void(NSClientPlayer) PlayerSpawn; virtual bool(void) IsTeamPlay; + virtual void(void) AddTeam1Kill; + virtual void(void) AddTeam2Kill; + virtual void(NSClientPlayer, entity) ScientistKill; }; /* Standard Hunting (0): @@ -51,8 +64,9 @@ class SHTeamRules:HLGameRules */ class SHGameHunt:SHTeamRules { - void(void) SHGameHunt; + + virtual void(void) RegisterSciDeath; }; /* Stealth Hunting (1): @@ -74,7 +88,7 @@ class SHGameSlaughter:HLGameRules }; /* Live in Fear (3): - Unique round-based gamemode where players have to only kill an evil randomly selected player controlled scientist causing chaos. Those who kill good scientists are punished with lost points. The evil scientist gains one point from every kill (NPC or Players). Scientists respawn. This is the only gamemode where there are no teams. + Unique round-based gamemode where players have to only kill an evil randomly selected player controlled scientist causing chaos. Those who kill good scientists are punished with lost points. The evil scientist gains one point from every kill (NPC or Players). Scientists respawn. */ class SHGameFear:HLGameRules { @@ -83,7 +97,7 @@ class SHGameFear:HLGameRules }; /* Madness (4): - Unique gamemode where scientists attack themselves and the players. Scientists inject players and NPCs only once with a poison that slowly drains their health to 0. The scientists also play a sound (sh/hide_laugh.wav) when they get a sucessful kill and are still alive. Scientists respawn. We use to have something similar, still in the logic? + Unique gamemode where scientists attack themselves and the players. Scientists inject players and NPCs only once with a poison that slowly drains their health to 0. The scientists also play a sound (sh/hide_laugh.wav) when they get a sucessful kill and are still alive. Scientists respawn. */ class SHGameMadness:HLGameRules { @@ -91,7 +105,6 @@ class SHGameMadness:HLGameRules void(void) SHGameMadness; }; - typedef enum { SHMODE_STANDARD = 0, @@ -101,5 +114,5 @@ typedef enum SHMODE_MADNESS } shmode_e; - var shmode_e autocvar_sv_realistic = SHMODE_SLAUGHTER; +var shmode_e g_chosen_mode; diff --git a/src/server/gamerules.qc b/src/server/gamerules.qc index 656bc14..d950eac 100644 --- a/src/server/gamerules.qc +++ b/src/server/gamerules.qc @@ -17,6 +17,26 @@ var int autocvar_sh_insanity = 10; var int autocvar_sv_playerkeepalive = TRUE; +void +HLGameRules::RestartRound(void) +{ + /* respawn all players and scientists */ + for (entity e = world; (e = find( e, ::classname, "player"));) { + PlayerSpawn((NSClientPlayer)e); + } + for (entity e = world; (e = find( e, ::classname, "monster_scientist"));) { + NSEntity sci = (NSEntity)e; + sci.Respawn(); + } + env_message_broadcast("New round, let's go!"); +} + +void +HLGameRules::RegisterSciDeath(void) +{ + CountScientists(); +} + bool HLGameRules::IsMultiplayer(void) { @@ -232,31 +252,15 @@ HLGameRules::PlayerPostFrame(NSClientPlayer pp) } void -HLGameRules::PlayerConnect(NSClientPlayer pl) +HLGameRules::CountScientists(void) { - if (Plugin_PlayerConnect(pl) == FALSE) - bprint(PRINT_HIGH, sprintf("%s connected\n", pl.netname)); -} + m_iScientistsAlive = 0; + for (entity s = world; (s = find(s, ::classname, "monster_scientist"));) { + if (s.solid == SOLID_BBOX || s.solid == SOLID_SLIDEBOX) + m_iScientistsAlive++; + } -void -HLGameRules::PlayerDisconnect(NSClientPlayer pl) -{ - bprint(PRINT_HIGH, sprintf("%s disconnected\n", pl.netname)); - - /* Make this unusable */ - pl.solid = SOLID_NOT; - pl.movetype = MOVETYPE_NONE; - pl.modelindex = 0; - pl.health = 0; - pl.takedamage = 0; - pl.SendFlags = PLAYER_MODELINDEX; -} - -void -HLGameRules::PlayerKill(NSClientPlayer pp) -{ - player pl = (player)pp; - Damage_Apply(pl, pl, pl.health, WEAPON_NONE, DMG_SKIP_ARMOR); + forceinfokey(world, "sci_count", sprintf("%i", m_iScientistsAlive)); } void @@ -334,7 +338,13 @@ HLGameRules::FrameStart(void) void HLGameRules::HLGameRules(void) { - CGameRules::CGameRules(); + forceinfokey(world, "teams", "0"); + forceinfokey(world, "team_1", ""); + forceinfokey(world, "team_2", ""); + forceinfokey(world, "teamscore_1", "0"); + forceinfokey(world, "teamscore_2", "0"); + forceinfokey(world, "teamkills_1", "0"); + forceinfokey(world, "teamkills_2", "0"); } /* TEAMPLAY ONLY LOGIC */ @@ -344,8 +354,71 @@ SHTeamRules::IsTeamPlay(void) return true; } +void +SHTeamRules::PlayerSpawn(NSClientPlayer cl) +{ + int red = 0; + int blue = 0; + + super::PlayerSpawn(cl); + + /* remove this if you want an auto-balance upon every death */ + if (cl.team != 0) + return; + + for (entity e = world; (e = find( e, ::classname, "player"));) { + if (e == cl) + continue; + if (e.team == 1) + red++; + if (e.team == 2) + blue++; + } + + /* assign to whatever team has fewer players */ + if (red > blue) + cl.team = 2; + else + cl.team = 1; + + forceinfokey(cl, "*team", sprintf("%d", cl.team)); +} + +void +SHTeamRules::ScientistKill(NSClientPlayer cl, entity sci) +{ + super::ScientistKill(cl, sci); + + if (cl.team == 2) + AddTeam2Kill(); + else if (cl.team == 1) + AddTeam1Kill(); +} + +void +SHTeamRules::AddTeam1Kill(void) +{ + m_iKillsTeam1++; + forceinfokey(world, "teamkills_1", sprintf("%i", m_iKillsTeam1)); +} + +void +SHTeamRules::AddTeam2Kill(void) +{ + m_iKillsTeam2++; + forceinfokey(world, "teamkills_2", sprintf("%i", m_iKillsTeam2)); +} + void SHTeamRules::SHTeamRules(void) { - + m_iKillsTeam1 = 0; + m_iKillsTeam2 = 0; + forceinfokey(world, "teamkills_1", sprintf("%i", m_iKillsTeam1)); + forceinfokey(world, "teamkills_2", sprintf("%i", m_iKillsTeam2)); + forceinfokey(world, "teams", "2"); + forceinfokey(world, "team_1", "Red"); + forceinfokey(world, "teamscore_1", "0"); + forceinfokey(world, "team_2", "Blue"); + forceinfokey(world, "teamscore_2", "0"); } diff --git a/src/server/gamerules_hunt.qc b/src/server/gamerules_hunt.qc index 0a8c3f7..7ed7784 100644 --- a/src/server/gamerules_hunt.qc +++ b/src/server/gamerules_hunt.qc @@ -1,3 +1,31 @@ +void +SHGameHunt::RegisterSciDeath(void) +{ + super::RegisterSciDeath(); + + if (m_iScientistsAlive > 0) + return; + + switch (g_chosen_mode) { + case SHMODE_STANDARD: + if (m_iKillsTeam1 > m_iKillsTeam2) { + m_iScoreTeam1++; + env_message_broadcast("Red team has won!"); + } else if (m_iKillsTeam1 > m_iKillsTeam2) { + m_iScoreTeam2++; + env_message_broadcast("Blue team has won!"); + } else { + env_message_broadcast("Both teams are tied!"); + } + + forceinfokey(world, "teamscore_1", sprintf("%i", m_iScoreTeam1)); + forceinfokey(world, "teamscore_2", sprintf("%i", m_iScoreTeam2)); + think = RestartRound; + nextthink = time + 5.0f; + break; + } +} + void SHGameHunt::SHGameHunt(void) { diff --git a/src/server/monster_scientist.qc b/src/server/monster_scientist.qc index ffde5d3..b4e3cca 100644 --- a/src/server/monster_scientist.qc +++ b/src/server/monster_scientist.qc @@ -235,22 +235,31 @@ monster_scientist::Pain(void) void monster_scientist::Death(void) { + bool deathcheck = false; + HLGameRules rules = (HLGameRules)g_grMode; + StartleAllies(); if (style != MONSTER_DEAD) { - HLGameRules rules = (HLGameRules)g_grMode; - - if (g_dmg_eAttacker.flags & FL_CLIENT) - rules.ScientistKill((player)g_dmg_eAttacker, (entity)this); - + rules.ScientistKill((player)g_dmg_eAttacker, (entity)this); Plugin_PlayerObituary(g_dmg_eAttacker, this, g_dmg_iWeapon, g_dmg_iHitBody, g_dmg_iDamage); - SetFrame(SCIA_DIE_SIMPLE + floor(random(0, 6))); Sound_Speak(this, "monster_scientist.die"); + deathcheck = true; } /* now mark our state as 'dead' */ super::Death(); + + /* now we'll tell our kill function about it, since we're now legally dead */ + if (deathcheck == true) { + rules.RegisterSciDeath(); + } + + /* will not respawn by themselves in this mode */ + if (g_chosen_mode == SHMODE_STANDARD) + return; + think = Respawn; nextthink = time + 10.0f; } @@ -267,13 +276,15 @@ monster_scientist::OnPlayerUse(void) void monster_scientist::Respawn(void) { + HLGameRules rules = (HLGameRules)g_grMode; + super::Respawn(); m_iFlags |= MONSTER_CANFOLLOW; PlayerUse = OnPlayerUse; health = base_health = Skill_GetValue("scientist_health", 20); takedamage = DAMAGE_YES; - if (autocvar_sh_scialert) { + if (autocvar_sh_scialert || g_chosen_mode == SHMODE_STANDARD) { m_iFlags |= MONSTER_FEAR; } @@ -299,6 +310,8 @@ monster_scientist::Respawn(void) m_flPitch = 100; netname = "Slick"; } + + rules.CountScientists(); } void diff --git a/src/server/server.qc b/src/server/server.qc index a4bd606..dc3841e 100644 --- a/src/server/server.qc +++ b/src/server/server.qc @@ -17,6 +17,8 @@ void Game_InitRules(void) { + g_chosen_mode = autocvar_sv_realistic; + switch (autocvar_sv_realistic) { case SHMODE_STANDARD: g_grMode = spawn(SHGameHunt);