Some more work done on the gamemodes. Team modes + standard hunt is now implemented but not quite tested. Still needs 'changeteam' cmd etc.

This commit is contained in:
Marco Cawthorne 2022-07-14 17:58:08 -07:00
parent eda8140127
commit fbb2df4b6e
Signed by: eukara
GPG key ID: CE2032F0A2882A22
8 changed files with 265 additions and 42 deletions

31
src/client/cmds.qc Normal file
View file

@ -0,0 +1,31 @@
/*
* 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.
*/
int
ClientGame_ConsoleCommand(void)
{
switch(argv(0)) {
case "+sciboard":
g_sciboard = true;
break;
case "-sciboard":
g_sciboard = false;
break;
default:
return (0);
}
return (1);
}

63
src/client/draw.qc Normal file
View file

@ -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();
}

View file

@ -19,12 +19,12 @@
../shared/include.src ../shared/include.src
../../../valve/src/client/damage.qc ../../../valve/src/client/damage.qc
../../../base/src/client/draw.qc draw.qc
../../../valve/src/client/init.qc ../../../valve/src/client/init.qc
../../../valve/src/client/flashlight.qc ../../../valve/src/client/flashlight.qc
../../../valve/src/client/player.qc ../../../valve/src/client/player.qc
../../../valve/src/client/entities.qc ../../../valve/src/client/entities.qc
../../../valve/src/client/cmds.qc cmds.qc
../../../valve/src/client/game_event.qc ../../../valve/src/client/game_event.qc
../../../valve/src/client/camera.qc ../../../valve/src/client/camera.qc
../../../valve/src/client/viewmodel.qc ../../../valve/src/client/viewmodel.qc

View file

@ -18,32 +18,45 @@
class HLGameRules:CGameRules class HLGameRules:CGameRules
{ {
int m_iScientistsAlive;
float m_flRestockTimer; float m_flRestockTimer;
float m_flBreakRespawnTimer; float m_flBreakRespawnTimer;
/* client */ /* client */
virtual void(NSClientPlayer) PlayerSpawn; virtual void(NSClientPlayer) PlayerSpawn;
virtual void(NSClientPlayer) PlayerConnect;
virtual void(NSClientPlayer) PlayerDisconnect;
virtual void(NSClientPlayer) PlayerKill;
virtual void(NSClientPlayer) PlayerDeath; virtual void(NSClientPlayer) PlayerDeath;
virtual void(NSClientPlayer) PlayerPostFrame; virtual void(NSClientPlayer) PlayerPostFrame;
virtual void(NSClientPlayer, entity) ScientistKill; virtual void(NSClientPlayer, entity) ScientistKill;
virtual void(void) RegisterSciDeath;
virtual void(NSClientPlayer) LevelDecodeParms; virtual void(NSClientPlayer) LevelDecodeParms;
virtual void(NSClientPlayer) LevelChangeParms; virtual void(NSClientPlayer) LevelChangeParms;
virtual void(void) LevelNewParms; virtual void(void) LevelNewParms;
virtual void(void) FrameStart; virtual void(void) FrameStart;
virtual bool(void) IsMultiplayer; virtual bool(void) IsMultiplayer;
virtual void(void) RestartRound;
virtual void(void) CountScientists;
void(void) HLGameRules; void(void) HLGameRules;
}; };
class SHTeamRules:HLGameRules class SHTeamRules:HLGameRules
{ {
int m_iKillsTeam1;
int m_iKillsTeam2;
int m_iScoreTeam1;
int m_iScoreTeam2;
void(void) SHTeamRules; void(void) SHTeamRules;
virtual void(NSClientPlayer) PlayerSpawn;
virtual bool(void) IsTeamPlay; virtual bool(void) IsTeamPlay;
virtual void(void) AddTeam1Kill;
virtual void(void) AddTeam2Kill;
virtual void(NSClientPlayer, entity) ScientistKill;
}; };
/* Standard Hunting (0): /* Standard Hunting (0):
@ -51,8 +64,9 @@ class SHTeamRules:HLGameRules
*/ */
class SHGameHunt:SHTeamRules class SHGameHunt:SHTeamRules
{ {
void(void) SHGameHunt; void(void) SHGameHunt;
virtual void(void) RegisterSciDeath;
}; };
/* Stealth Hunting (1): /* Stealth Hunting (1):
@ -74,7 +88,7 @@ class SHGameSlaughter:HLGameRules
}; };
/* Live in Fear (3): /* 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 class SHGameFear:HLGameRules
{ {
@ -83,7 +97,7 @@ class SHGameFear:HLGameRules
}; };
/* Madness (4): /* 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 class SHGameMadness:HLGameRules
{ {
@ -91,7 +105,6 @@ class SHGameMadness:HLGameRules
void(void) SHGameMadness; void(void) SHGameMadness;
}; };
typedef enum typedef enum
{ {
SHMODE_STANDARD = 0, SHMODE_STANDARD = 0,
@ -101,5 +114,5 @@ typedef enum
SHMODE_MADNESS SHMODE_MADNESS
} shmode_e; } shmode_e;
var shmode_e autocvar_sv_realistic = SHMODE_SLAUGHTER; var shmode_e autocvar_sv_realistic = SHMODE_SLAUGHTER;
var shmode_e g_chosen_mode;

View file

@ -17,6 +17,26 @@
var int autocvar_sh_insanity = 10; var int autocvar_sh_insanity = 10;
var int autocvar_sv_playerkeepalive = TRUE; 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 bool
HLGameRules::IsMultiplayer(void) HLGameRules::IsMultiplayer(void)
{ {
@ -232,31 +252,15 @@ HLGameRules::PlayerPostFrame(NSClientPlayer pp)
} }
void void
HLGameRules::PlayerConnect(NSClientPlayer pl) HLGameRules::CountScientists(void)
{ {
if (Plugin_PlayerConnect(pl) == FALSE) m_iScientistsAlive = 0;
bprint(PRINT_HIGH, sprintf("%s connected\n", pl.netname)); for (entity s = world; (s = find(s, ::classname, "monster_scientist"));) {
if (s.solid == SOLID_BBOX || s.solid == SOLID_SLIDEBOX)
m_iScientistsAlive++;
} }
void forceinfokey(world, "sci_count", sprintf("%i", m_iScientistsAlive));
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);
} }
void void
@ -334,7 +338,13 @@ HLGameRules::FrameStart(void)
void void
HLGameRules::HLGameRules(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 */ /* TEAMPLAY ONLY LOGIC */
@ -344,8 +354,71 @@ SHTeamRules::IsTeamPlay(void)
return true; 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 void
SHTeamRules::SHTeamRules(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");
} }

View file

@ -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 void
SHGameHunt::SHGameHunt(void) SHGameHunt::SHGameHunt(void)
{ {

View file

@ -235,22 +235,31 @@ monster_scientist::Pain(void)
void void
monster_scientist::Death(void) monster_scientist::Death(void)
{ {
bool deathcheck = false;
HLGameRules rules = (HLGameRules)g_grMode;
StartleAllies(); StartleAllies();
if (style != MONSTER_DEAD) { 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); Plugin_PlayerObituary(g_dmg_eAttacker, this, g_dmg_iWeapon, g_dmg_iHitBody, g_dmg_iDamage);
SetFrame(SCIA_DIE_SIMPLE + floor(random(0, 6))); SetFrame(SCIA_DIE_SIMPLE + floor(random(0, 6)));
Sound_Speak(this, "monster_scientist.die"); Sound_Speak(this, "monster_scientist.die");
deathcheck = true;
} }
/* now mark our state as 'dead' */ /* now mark our state as 'dead' */
super::Death(); 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; think = Respawn;
nextthink = time + 10.0f; nextthink = time + 10.0f;
} }
@ -267,13 +276,15 @@ monster_scientist::OnPlayerUse(void)
void void
monster_scientist::Respawn(void) monster_scientist::Respawn(void)
{ {
HLGameRules rules = (HLGameRules)g_grMode;
super::Respawn(); super::Respawn();
m_iFlags |= MONSTER_CANFOLLOW; m_iFlags |= MONSTER_CANFOLLOW;
PlayerUse = OnPlayerUse; PlayerUse = OnPlayerUse;
health = base_health = Skill_GetValue("scientist_health", 20); health = base_health = Skill_GetValue("scientist_health", 20);
takedamage = DAMAGE_YES; takedamage = DAMAGE_YES;
if (autocvar_sh_scialert) { if (autocvar_sh_scialert || g_chosen_mode == SHMODE_STANDARD) {
m_iFlags |= MONSTER_FEAR; m_iFlags |= MONSTER_FEAR;
} }
@ -299,6 +310,8 @@ monster_scientist::Respawn(void)
m_flPitch = 100; m_flPitch = 100;
netname = "Slick"; netname = "Slick";
} }
rules.CountScientists();
} }
void void

View file

@ -17,6 +17,8 @@
void void
Game_InitRules(void) Game_InitRules(void)
{ {
g_chosen_mode = autocvar_sv_realistic;
switch (autocvar_sv_realistic) { switch (autocvar_sv_realistic) {
case SHMODE_STANDARD: case SHMODE_STANDARD:
g_grMode = spawn(SHGameHunt); g_grMode = spawn(SHGameHunt);