]> git.rm.cloudns.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Changed to Murder in Megaerebus Manor, fixes and enhanced bots Civilians and Sleuths...
authorLegendaryGuard <rootuser999@gmail.com>
Fri, 26 Mar 2021 23:28:47 +0000 (00:28 +0100)
committerLegendaryGuard <rootuser999@gmail.com>
Fri, 26 Mar 2021 23:28:47 +0000 (00:28 +0100)
36 files changed:
gamemodes-client.cfg
gamemodes-server.cfg
gfx/menu/luma/gametype_mmm.tga [new file with mode: 0644]
gfx/menu/luma/gametype_ttt.tga [deleted file]
gfx/menu/luminos/gametype_mmm.tga [new file with mode: 0644]
gfx/menu/luminos/gametype_ttt.tga [deleted file]
gfx/menu/wickedx/gametype_mmm.tga [new file with mode: 0644]
gfx/menu/wickedx/gametype_ttt.tga [deleted file]
gfx/menu/xaw/gametype_mmm.tga [new file with mode: 0644]
gfx/menu/xaw/gametype_ttt.tga [deleted file]
notifications.cfg
qcsrc/common/ent_cs.qc
qcsrc/common/gamemodes/gamemode/_mod.inc
qcsrc/common/gamemodes/gamemode/_mod.qh
qcsrc/common/gamemodes/gamemode/mmm/_mod.inc [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/mmm/_mod.qh [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/mmm/cl_mmm.qc [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/mmm/cl_mmm.qh [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/mmm/mmm.qc [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/mmm/mmm.qh [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/mmm/sv_mmm.qc [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/mmm/sv_mmm.qh [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/ttt/_mod.inc [deleted file]
qcsrc/common/gamemodes/gamemode/ttt/_mod.qh [deleted file]
qcsrc/common/gamemodes/gamemode/ttt/cl_ttt.qc [deleted file]
qcsrc/common/gamemodes/gamemode/ttt/cl_ttt.qh [deleted file]
qcsrc/common/gamemodes/gamemode/ttt/sv_ttt.qc [deleted file]
qcsrc/common/gamemodes/gamemode/ttt/sv_ttt.qh [deleted file]
qcsrc/common/gamemodes/gamemode/ttt/ttt.qc [deleted file]
qcsrc/common/gamemodes/gamemode/ttt/ttt.qh [deleted file]
qcsrc/common/notifications/all.inc
qcsrc/common/notifications/all.qh
qcsrc/common/scores.qh
qcsrc/common/stats.qh
qcsrc/menu/xonotic/util.qc
qcsrc/server/world.qc

index 633b73fe280b6c0fb731e83226cfb248197a9d1f..aa8daa67ef0983e810c5e12809acae907af26e8a 100644 (file)
@@ -32,7 +32,7 @@ alias cl_hook_gamestart_ka
 alias cl_hook_gamestart_ft
 alias cl_hook_gamestart_inv
 alias cl_hook_gamestart_duel
-alias cl_hook_gamestart_ttt //LegendGuard adds ttt client hook for TTT 20-02-2021
+alias cl_hook_gamestart_mmm //LegendGuard adds mmm client hook for MMM 20-02-2021
 alias cl_hook_gameend "rpn /cl_matchcount dup load 1 + =" // increase match count every time a game ends
 alias cl_hook_shutdown
 alias cl_hook_activeweapon
index 6e058ec4ef260392a0f640058322c1899e9f4c91..f7bbfc4bd4d64fdfdb9e7aba2d5c2c4794207c20 100644 (file)
@@ -29,7 +29,7 @@ alias sv_hook_gamestart_ka
 alias sv_hook_gamestart_ft
 alias sv_hook_gamestart_inv
 alias sv_hook_gamestart_duel
-alias sv_hook_gamestart_ttt //LegendGuard adds ttt hook for TTT 20-02-2021
+alias sv_hook_gamestart_mmm //LegendGuard adds mmm hook for MMM 20-02-2021
 // there is currently no hook for when the match is restarted
 // see sv_hook_readyrestart for previous uses of this hook
 //alias sv_hook_gamerestart
@@ -59,7 +59,7 @@ alias sv_vote_gametype_hook_ons
 alias sv_vote_gametype_hook_rc
 alias sv_vote_gametype_hook_tdm
 alias sv_vote_gametype_hook_duel
-alias sv_vote_gametype_hook_ttt //LegendGuard adds ttt hook for TTT 20-02-2021
+alias sv_vote_gametype_hook_mmm //LegendGuard adds mmm hook for MMM 20-02-2021
 
 // Example preset to allow 1v1ctf to be used for the gametype voting screen.
 // Aliases can have max 31 chars so the gametype can have max 9 chars.
@@ -210,13 +210,13 @@ set g_duel_respawn_delay_large_count 0
 set g_duel_respawn_delay_max 0
 set g_duel_respawn_waves 0
 set g_duel_weapon_stay 0
-set g_ttt_respawn_delay_small 0 //LegendGuard adds ttt cvars for TTT 20-02-2021
-set g_ttt_respawn_delay_small_count 0
-set g_ttt_respawn_delay_large 0
-set g_ttt_respawn_delay_large_count 0
-set g_ttt_respawn_delay_max 0
-set g_ttt_respawn_waves 0
-set g_ttt_weapon_stay 0
+set g_mmm_respawn_delay_small 0 //LegendGuard adds mmm cvars for MMM 20-02-2021
+set g_mmm_respawn_delay_small_count 0
+set g_mmm_respawn_delay_large 0
+set g_mmm_respawn_delay_large_count 0
+set g_mmm_respawn_delay_max 0
+set g_mmm_respawn_waves 0
+set g_mmm_weapon_stay 0
 
 
 // =========
@@ -566,16 +566,21 @@ set g_duel 0 "Duel: frag the opponent more in a one versus one arena battle"
 set g_duel_with_powerups 0 "Enable powerups to spawn in the duel gamemode"
 set g_duel_not_dm_maps 0 "when this is set, DM maps will NOT be listed in duel"
 
-//LegendGuard adds ttt cvars for TTT 20-02-2021
+//LegendGuard adds mmm cvars for MMM 20-02-2021
 // ==========
-//  trouble in terrorist town
+//  murder in megaerebus manor
 // ==========
-set g_ttt 0 "Trouble in Terrorist Town: A group of space terrorists have traitors among them. Traitors must kill terrorists, while the terrorists have to try to find and kill the traitors"
-set g_ttt_not_lms_maps 0 "when this is set, LMS maps will NOT be listed in ttt"
-//set g_ttt_traitor_count 0.25 "number of players who will become traitors, set between 0 and 0.9 to use a multiplier of the current players, or 1 and above to specify an exact number of players"
-set g_ttt_punish_teamkill 0 "kill the player when they kill an ally"
-set g_ttt_reward_innocent 1 "give a point to all innocent players if the round timelimit is reached, in addition to the points given for kills"
-set g_ttt_warmup 10 "how long the players will have time to run around the map before the round starts"
-set g_ttt_round_timelimit 180 "round time limit in seconds"
-set g_ttt_max_karma_points 1000 "limit of maximum number of karma points will have in the server"
-set g_ttt_min_karma_points 400 "limit where number of karma points can be reached when are being decreased"
\ No newline at end of file
+set g_mmm 0 "Murder in Megaerebus Manor: A group of space civilians have murderers among them. Murderers must kill civilians, while the civilians have to try to find and kill the murderers"
+set g_mmm_not_lms_maps 0 "when this is set, LMS maps will NOT be listed in mmm"
+set g_mmm_civilian_count 0.625 "number of players who will become civilians, set between 0 and 0.9 to use a multiplier of the current players, or 1 and above to specify an exact number of players"
+//set g_mmm_murderer_count 0.25 "number of players who will become murderers, set between 0 and 0.9 to use a multiplier of the current players, or 1 and above to specify an exact number of players"
+set g_mmm_punish_teamkill 0 "kill the player when they kill an ally"
+set g_mmm_reward_civilian 1 "give a point to all civilian players if the round timelimit is reached, in addition to the points given for kills"
+set g_mmm_warmup 10 "how long the players will have time to run around the map before the round starts"
+set g_mmm_round_timelimit 180 "round time limit in seconds"
+set g_mmm_max_karma_points 1000 "limit of maximum number of karma points will have in the server"
+set g_mmm_min_karma_points 400 "limit where number of karma points can be reached when are being decreased"
+set g_mmm_karma_bankick_tool 0 "tool for strict rules when karma is low: '0' forces player to spec, '1' kicks player, '2' bans player"
+set g_mmm_karma_bantime 1800 "number of seconds to ban someone with very low karma"
+set g_mmm_karma_damageactive 1 "enable karma damage rule. If a player's karma is low, they will not do as much damage as a player who has high or full karma"
+set g_mmm_reward_sleuth 1 "give a point to all sleuth players if investigated corpses"
\ No newline at end of file
diff --git a/gfx/menu/luma/gametype_mmm.tga b/gfx/menu/luma/gametype_mmm.tga
new file mode 100644 (file)
index 0000000..481c621
Binary files /dev/null and b/gfx/menu/luma/gametype_mmm.tga differ
diff --git a/gfx/menu/luma/gametype_ttt.tga b/gfx/menu/luma/gametype_ttt.tga
deleted file mode 100644 (file)
index d36db5d..0000000
Binary files a/gfx/menu/luma/gametype_ttt.tga and /dev/null differ
diff --git a/gfx/menu/luminos/gametype_mmm.tga b/gfx/menu/luminos/gametype_mmm.tga
new file mode 100644 (file)
index 0000000..8bacd80
Binary files /dev/null and b/gfx/menu/luminos/gametype_mmm.tga differ
diff --git a/gfx/menu/luminos/gametype_ttt.tga b/gfx/menu/luminos/gametype_ttt.tga
deleted file mode 100644 (file)
index 7fd5a53..0000000
Binary files a/gfx/menu/luminos/gametype_ttt.tga and /dev/null differ
diff --git a/gfx/menu/wickedx/gametype_mmm.tga b/gfx/menu/wickedx/gametype_mmm.tga
new file mode 100644 (file)
index 0000000..8bacd80
Binary files /dev/null and b/gfx/menu/wickedx/gametype_mmm.tga differ
diff --git a/gfx/menu/wickedx/gametype_ttt.tga b/gfx/menu/wickedx/gametype_ttt.tga
deleted file mode 100644 (file)
index 7fd5a53..0000000
Binary files a/gfx/menu/wickedx/gametype_ttt.tga and /dev/null differ
diff --git a/gfx/menu/xaw/gametype_mmm.tga b/gfx/menu/xaw/gametype_mmm.tga
new file mode 100644 (file)
index 0000000..938b529
Binary files /dev/null and b/gfx/menu/xaw/gametype_mmm.tga differ
diff --git a/gfx/menu/xaw/gametype_ttt.tga b/gfx/menu/xaw/gametype_ttt.tga
deleted file mode 100644 (file)
index f0be4ad..0000000
Binary files a/gfx/menu/xaw/gametype_ttt.tga and /dev/null differ
index cfcff6f7c31d93facb46b2322cf45d0dd0816a8a..3028b11b970330dd76b7a6451c9667b5d5232ce3 100644 (file)
@@ -286,9 +286,9 @@ seta notification_INFO_SUPERWEAPON_PICKUP "1" "0 = off, 1 = print to console, 2
 seta notification_INFO_TEAMCHANGE_LARGERTEAM "1" "0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
 seta notification_INFO_TEAMCHANGE_NOTALLOWED "1" "0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
 
-//LegendGuard adds ttt notifications for TTT 20-02-2021
-seta notification_INFO_TTT_TRAITOR_WIN "1" "0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
-seta notification_INFO_TTT_INNOCENT_WIN "1" "0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
+//LegendGuard adds mmm notifications for MMM 20-02-2021
+seta notification_INFO_MMM_MURDERER_WIN "1" "0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
+seta notification_INFO_MMM_CIVILIAN_WIN "1" "0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
 
 seta notification_INFO_VERSION_BETA "1" "0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
 seta notification_INFO_VERSION_OLD "2" "0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
@@ -543,12 +543,12 @@ seta notification_CENTER_TEAMCHANGE_SPECTATE "1" "0 = off, 1 = centerprint"
 seta notification_CENTER_TEAMCHANGE_SUICIDE "1" "0 = off, 1 = centerprint"
 seta notification_CENTER_TIMEOUT_BEGINNING "1" "0 = off, 1 = centerprint"
 seta notification_CENTER_TIMEOUT_ENDING "1" "0 = off, 1 = centerprint"
-//LegendGuard adds ttt notification for TTT 20-02-2021
-seta notification_CENTER_TTT_TRAITOR "1" "0 = off, 1 = centerprint"
-seta notification_CENTER_TTT_TRAITOR_WIN "1" "0 = off, 1 = centerprint"
-seta notification_CENTER_TTT_INNOCENT "1" "0 = off, 1 = centerprint"
-seta notification_CENTER_TTT_INNOCENT_WIN "1" "0 = off, 1 = centerprint"
-seta notification_CENTER_TTT_DETECTIVE "1" "0 = off, 1 = centerprint"
+//LegendGuard adds mmm notification for MMM 20-02-2021
+seta notification_CENTER_MMM_MURDERER "1" "0 = off, 1 = centerprint"
+seta notification_CENTER_MMM_MURDERER_WIN "1" "0 = off, 1 = centerprint"
+seta notification_CENTER_MMM_CIVILIAN "1" "0 = off, 1 = centerprint"
+seta notification_CENTER_MMM_CIVILIAN_WIN "1" "0 = off, 1 = centerprint"
+seta notification_CENTER_MMM_SLEUTH "1" "0 = off, 1 = centerprint"
 
 seta notification_CENTER_VEHICLE_ENTER "1" "0 = off, 1 = centerprint"
 seta notification_CENTER_VEHICLE_ENTER_GUNNER "1" "0 = off, 1 = centerprint"
index 5f0d788970fbcb4bbddc866baa31c6a46c1e572e..713ed6f990b63514fe542bfcd29be83419c1f143 100644 (file)
@@ -157,11 +157,11 @@ ENTCS_PROP(SOLID, true, sv_solid, solid, ENTCS_SET_NORMAL,
        { WriteByte(chan, ent.sv_solid); },
        { ent.sv_solid = ReadByte(); })
 
-//LegendGuard adds ENTCS_PROP from TTT 20-02-2021
-// gamemode specific player ttt status (independent of score and frags)
-ENTCS_PROP(TTT_STATUS, true, ttt_status, ttt_status, ENTCS_SET_NORMAL,
-       { WriteShort(chan, ent.ttt_status); },
-       { ent.ttt_status = ReadShort(); })
+//LegendGuard adds ENTCS_PROP from MMM 20-02-2021
+// gamemode specific player mmm status (independent of score and frags)
+ENTCS_PROP(MMM_STATUS, true, mmm_status, mmm_status, ENTCS_SET_NORMAL,
+       { WriteShort(chan, ent.mmm_status); },
+       { ent.mmm_status = ReadShort(); })
 
 #ifdef SVQC
 
index 759f00def8f49e6ccefb4f2a4bbcaa61d8e93c07..aed8d748b06c40bf875483729a9fcf963494c4df 100644 (file)
@@ -12,8 +12,8 @@
 #include <common/gamemodes/gamemode/keepaway/_mod.inc>
 #include <common/gamemodes/gamemode/keyhunt/_mod.inc>
 #include <common/gamemodes/gamemode/lms/_mod.inc>
+#include <common/gamemodes/gamemode/mmm/_mod.inc> //LegendGuard adds _mod.inc for Murder in Megaerebus Manor 20-02-2021
 #include <common/gamemodes/gamemode/nexball/_mod.inc>
 #include <common/gamemodes/gamemode/onslaught/_mod.inc>
 #include <common/gamemodes/gamemode/race/_mod.inc>
-#include <common/gamemodes/gamemode/ttt/_mod.inc> //LegendGuard adds _mod.inc for Trouble In Terrorist Town 20-02-2021
 #include <common/gamemodes/gamemode/tdm/_mod.inc>
\ No newline at end of file
index ef725161bd9a24349a79fff843ec993b3a94ab95..3631a218be6b6bed0e212083b41565b6a4232f34 100644 (file)
@@ -12,8 +12,8 @@
 #include <common/gamemodes/gamemode/keepaway/_mod.qh>
 #include <common/gamemodes/gamemode/keyhunt/_mod.qh>
 #include <common/gamemodes/gamemode/lms/_mod.qh>
+#include <common/gamemodes/gamemode/mmm/_mod.qh> //LegendGuard adds _mod.qh for Murder in Megaerebus Manor 20-02-2021
 #include <common/gamemodes/gamemode/nexball/_mod.qh>
 #include <common/gamemodes/gamemode/onslaught/_mod.qh>
 #include <common/gamemodes/gamemode/race/_mod.qh>
-#include <common/gamemodes/gamemode/ttt/_mod.qh> //LegendGuard adds _mod.qh for Trouble In Terrorist Town 20-02-2021
 #include <common/gamemodes/gamemode/tdm/_mod.qh>
\ No newline at end of file
diff --git a/qcsrc/common/gamemodes/gamemode/mmm/_mod.inc b/qcsrc/common/gamemodes/gamemode/mmm/_mod.inc
new file mode 100644 (file)
index 0000000..32ad9f7
--- /dev/null
@@ -0,0 +1,8 @@
+// generated file; do not modify
+#include <common/gamemodes/gamemode/mmm/mmm.qc>
+#ifdef CSQC
+    #include <common/gamemodes/gamemode/mmm/cl_mmm.qc>
+#endif
+#ifdef SVQC
+    #include <common/gamemodes/gamemode/mmm/sv_mmm.qc>
+#endif
diff --git a/qcsrc/common/gamemodes/gamemode/mmm/_mod.qh b/qcsrc/common/gamemodes/gamemode/mmm/_mod.qh
new file mode 100644 (file)
index 0000000..03ae61b
--- /dev/null
@@ -0,0 +1,8 @@
+// generated file; do not modify
+#include <common/gamemodes/gamemode/mmm/mmm.qh>
+#ifdef CSQC
+    #include <common/gamemodes/gamemode/mmm/cl_mmm.qh>
+#endif
+#ifdef SVQC
+    #include <common/gamemodes/gamemode/mmm/sv_mmm.qh>
+#endif
diff --git a/qcsrc/common/gamemodes/gamemode/mmm/cl_mmm.qc b/qcsrc/common/gamemodes/gamemode/mmm/cl_mmm.qc
new file mode 100644 (file)
index 0000000..8882600
--- /dev/null
@@ -0,0 +1,103 @@
+#include "cl_mmm.qh"
+
+#include <client/draw.qh>
+#include <client/hud/panel/modicons.qh>
+
+void HUD_Mod_MMM(vector pos, vector mySize)
+{
+       mod_active = 1; // mmm should always show the mod HUD
+
+       int mystatus = entcs_receiver(player_localnum).mmm_status;
+       string player_text = "";
+       vector player_color = '1 1 1';
+       //string player_icon = "";
+       if(mystatus == MMM_STATUS_MURDERER)
+       {
+               player_text = _("Murderer");
+               player_color = '1 0 0';
+               //player_icon = "player_red";
+       }
+       else if(mystatus == MMM_STATUS_CIVILIAN)
+       {
+               player_text = _("Civilian");
+               player_color = '0 1 0';
+               //player_icon = "player_neutral";
+       }
+       else if(mystatus == MMM_STATUS_SLEUTH)
+       {
+               player_text = _("Sleuth");
+               player_color = '0 0 1';
+               //player_icon = "player_blue";
+       }
+       else
+       {
+               // if the player has no valid status, don't draw anything
+               return;
+       }
+
+       string time_text = string_null;
+       vector timer_color = '1 1 1';
+       if(!STAT(GAME_STOPPED) && !warmup_stage && STAT(MMM_ROUNDTIMER) > 0)
+       {
+               float timeleft = max(0, STAT(MMM_ROUNDTIMER) - time);
+               timeleft = ceil(timeleft);
+               float minutesLeft = floor(timeleft / 60);
+               time_text = seconds_tostring(timeleft);
+               if(intermission_time || minutesLeft >= 5 || warmup_stage || STAT(MMM_ROUNDTIMER) == 0)
+                       timer_color = '1 1 1'; //white
+               else if(minutesLeft >= 1)
+                       timer_color = '1 1 0'; //yellow
+               else
+                       timer_color = '1 0 0'; //red
+       }
+
+       //drawpic_aspect_skin(pos, player_icon, vec2(0.5 * mySize.x, mySize.y), '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+       if(!time_text)
+               drawstring_aspect(pos, player_text, vec2(mySize.x, mySize.y), player_color, panel_fg_alpha, DRAWFLAG_NORMAL);
+       else
+       {
+               drawstring_aspect(pos, player_text, vec2(0.5 * mySize.x, mySize.y), player_color, panel_fg_alpha, DRAWFLAG_NORMAL);
+               drawstring_aspect(pos + eX * (0.5 * mySize.x), time_text, vec2(0.5 * mySize.x, mySize.y), timer_color, panel_fg_alpha, DRAWFLAG_NORMAL);
+       }
+}
+
+REGISTER_MUTATOR(cl_mmm, true);
+
+MUTATOR_HOOKFUNCTION(cl_mmm, ForcePlayercolors_Skip, CBC_ORDER_LAST)
+{
+       if(!ISGAMETYPE(MMM))
+               return false;
+               
+       entity player = M_ARGV(0, entity);
+       entity e = entcs_receiver(player.entnum - 1);
+       int otherplayer_status = ((e) ? e.mmm_status : 0);
+       int mystatus = entcs_receiver(player_localnum).mmm_status;
+
+       int plcolor = MMM_COLOR_CIVILIAN; // default to civilian
+
+       if((mystatus == MMM_STATUS_MURDERER || intermission || STAT(GAME_STOPPED)) && otherplayer_status == MMM_STATUS_MURDERER)
+       {
+               plcolor = MMM_COLOR_MURDERER;
+       }
+       
+       //LegendGuard adds CIVILIAN part 21-02-2021
+       if((mystatus == MMM_STATUS_CIVILIAN || intermission || STAT(GAME_STOPPED)) && otherplayer_status == MMM_STATUS_CIVILIAN)
+       {
+               plcolor = MMM_COLOR_CIVILIAN;
+       }
+
+       //LegendGuard adds if sentence for Sleuth model color which will shown for everyone 21-02-2021
+       if (otherplayer_status == MMM_STATUS_SLEUTH)
+       {
+               plcolor = MMM_COLOR_SLEUTH;
+       }
+
+       player.colormap = 1024 + plcolor;
+       return true;
+}
+
+MUTATOR_HOOKFUNCTION(cl_mmm, DrawScoreboard_Force)
+{
+       // show the scoreboard when the round ends, so players can see who the murderer was
+       return STAT(GAME_STOPPED);
+}
diff --git a/qcsrc/common/gamemodes/gamemode/mmm/cl_mmm.qh b/qcsrc/common/gamemodes/gamemode/mmm/cl_mmm.qh
new file mode 100644 (file)
index 0000000..154a127
--- /dev/null
@@ -0,0 +1,3 @@
+#pragma once
+
+void HUD_Mod_MMM(vector pos, vector mySize);
diff --git a/qcsrc/common/gamemodes/gamemode/mmm/mmm.qc b/qcsrc/common/gamemodes/gamemode/mmm/mmm.qc
new file mode 100644 (file)
index 0000000..7228ebc
--- /dev/null
@@ -0,0 +1 @@
+#include "mmm.qh"
diff --git a/qcsrc/common/gamemodes/gamemode/mmm/mmm.qh b/qcsrc/common/gamemodes/gamemode/mmm/mmm.qh
new file mode 100644 (file)
index 0000000..a537949
--- /dev/null
@@ -0,0 +1,45 @@
+#pragma once
+
+#include <common/gamemodes/gamemode/lms/lms.qh>
+#include <common/mapinfo.qh>
+
+#ifdef CSQC
+void HUD_Mod_MMM(vector pos, vector mySize);
+#endif
+CLASS(MurderinMegaerebusManor, Gametype)
+    INIT(MurderinMegaerebusManor)
+    {
+        this.gametype_init(this, _("Murder in Megaerebus Manor"),"mmm","g_mmm",GAMETYPE_FLAG_USEPOINTS,"","timelimit=30 pointlimit=20",_("A group of space civilians have murderers among them. Murderers must kill civilians, while the civilians have to try to find and kill the murderers"));
+    }
+    METHOD(MurderinMegaerebusManor, m_isAlwaysSupported, bool(Gametype this, int spawnpoints, float diameter))
+    {
+        return true;
+    }
+    METHOD(MurderinMegaerebusManor, m_isForcedSupported, bool(Gametype this))
+    {
+        if(!cvar("g_mmm_not_lms_maps"))
+        {
+            // if this is unset, all LMS maps support MurderinMegaerebusManor too
+            if(!(MapInfo_Map_supportedGametypes & this.m_flags) && (MapInfo_Map_supportedGametypes & MAPINFO_TYPE_LMS.m_flags))
+                return true; // TODO: references another gametype (alternatively, we could check which gamemodes are always enabled and append this if any are supported)
+        }
+        return false;
+    }
+#ifdef CSQC
+    ATTRIB(MurderinMegaerebusManor, m_modicons, void(vector pos, vector mySize), HUD_Mod_MMM);
+#endif
+ENDCLASS(MurderinMegaerebusManor)
+REGISTER_GAMETYPE(MMM, NEW(MurderinMegaerebusManor));
+
+#ifdef GAMEQC
+// shared state signalling the player's mmm status
+.int mmm_status;
+const int MMM_STATUS_CIVILIAN = 1;
+const int MMM_STATUS_MURDERER = 2;
+const int MMM_STATUS_SLEUTH = 3;
+
+// hardcoded player colors for mmm
+const int MMM_COLOR_SLEUTH = 221; // blue
+const int MMM_COLOR_CIVILIAN = 51; // green
+const int MMM_COLOR_MURDERER = 68; // red
+#endif
diff --git a/qcsrc/common/gamemodes/gamemode/mmm/sv_mmm.qc b/qcsrc/common/gamemodes/gamemode/mmm/sv_mmm.qc
new file mode 100644 (file)
index 0000000..14795bb
--- /dev/null
@@ -0,0 +1,935 @@
+#include "sv_mmm.qh"
+
+//set g_mmm_sleuth_count 0.125 "number of players who will become sleuths, set between 0 and 0.9 to use a multiplier of the current players, or 1 and above to specify an exact number of players"
+//float autocvar_g_mmm_sleuth_count = 0.125; //I don't think that it won't be used...
+float autocvar_g_mmm_civilian_count = 0.625;
+//float autocvar_g_mmm_murderer_count = 0.25;
+float autocvar_g_mmm_round_timelimit = 180;
+float autocvar_g_mmm_warmup = 10;
+bool autocvar_g_mmm_punish_teamkill = false;
+bool autocvar_g_mmm_reward_civilian = true;
+bool autocvar_g_mmm_reward_sleuth = true; //sleuth reward if investigated corpses
+float autocvar_g_mmm_max_karma_points = 1000; //LegendGuard sets Karma points 21-02-2021
+float autocvar_g_mmm_min_karma_points = 400;
+int autocvar_g_mmm_karma_bankick_tool = 0; //LegendGuard sets a ban tool for server admins 11-03-2021
+float autocvar_g_mmm_karma_bantime = 1800; //karma ban seconds
+bool autocvar_g_mmm_karma_damageactive = true; //LegendGuard sets Karma damage setting if active 20-03-2021
+
+// Sleuth is a created team, this team is added inside Civilians team
+
+void mmm_FakeTimeLimit(entity e, float t)
+{
+       if(!IS_REAL_CLIENT(e))
+               return;
+#if 0
+       msg_entity = e;
+       WriteByte(MSG_ONE, 3); // svc_updatestat
+       WriteByte(MSG_ONE, 236); // STAT_TIMELIMIT
+       if(t < 0)
+               WriteCoord(MSG_ONE, autocvar_timelimit);
+       else
+               WriteCoord(MSG_ONE, (t + 1) / 60);
+#else
+       STAT(MMM_ROUNDTIMER, e) = t;
+#endif
+}
+
+void nades_Clear(entity player);
+
+void karma_Control(entity it)
+{
+       float masksize = autocvar_g_ban_default_masksize;
+       float bantime = autocvar_g_mmm_karma_bantime;
+       if(it.karmapoints >= autocvar_g_mmm_max_karma_points)
+       {
+               //Resets karmapoints to maintain the maximum
+               //PrintToChatAll("^3REWARD ^1MAXIMUM RESET");
+               GameRules_scoring_add(it, MMM_KARMA, autocvar_g_mmm_max_karma_points - it.karmapoints);
+               it.karmapoints = autocvar_g_mmm_max_karma_points;
+       }
+       else if(it.karmapoints <= autocvar_g_mmm_min_karma_points)
+       {
+               switch (autocvar_g_mmm_karma_bankick_tool)
+               {
+                       //force to spec
+                       case 0: PutObserverInServer(it); return;
+                       //kick
+                       case 1: dropclient(it); return;
+                       //ban and kick
+                       case 2: Ban_KickBanClient(it, bantime, masksize, "Too low karma"); return;
+                       //force to spec
+                       default: PutObserverInServer(it); return;
+               }
+       }
+}
+
+void karmaLoseDifference(entity attacker, entity target)
+{
+       //BASIC MATH THEORY: example: 1000 * 0.3 * (0.1 + 0.4) * 0.25 // karma points reduce when player attacked to other player
+       if (target.karmapoints < attacker.karmapoints)
+       {       
+               float decreasekarma = - ( target.karmapoints * random() * ( 0.1 + random() ) * 0.25 );
+               GameRules_scoring_add(attacker, MMM_KARMA, decreasekarma);
+               attacker.karmapoints = attacker.karmapoints + decreasekarma;
+       }
+       else if (target.karmapoints > attacker.karmapoints)
+       {
+               float decreasekarma = - ( target.karmapoints * random() * ( 0.1 + random() ) * 0.25 );
+               GameRules_scoring_add(attacker, MMM_KARMA, decreasekarma);
+               attacker.karmapoints = attacker.karmapoints + decreasekarma;
+       }
+       else
+       {
+               float decreasekarma = - ( target.karmapoints * random() * ( 0.1 + random() ) * 0.25 );
+               GameRules_scoring_add(attacker, MMM_KARMA, decreasekarma);
+               attacker.karmapoints = attacker.karmapoints + decreasekarma;
+       }
+}
+
+void karmaWinDifference(entity it)
+{
+       GameRules_scoring_add(it, SCORE, 1); // reward civilians who make it to the end of the round time limit
+       float increasekarma = ( autocvar_g_mmm_min_karma_points * random() * ( 0.1 + random() ) * 0.12 );
+       GameRules_scoring_add(it, MMM_KARMA, increasekarma);
+       it.karmapoints = it.karmapoints + increasekarma;
+}
+
+void mmm_UpdateScores(bool timed_out)
+{
+       // give players their hard-earned kills now that the round is over
+       FOREACH_CLIENT(true,
+       {
+               it.totalfrags += it.mmm_validkills;
+               if(it.mmm_validkills)
+               {
+                       GameRules_scoring_add(it, SCORE, it.mmm_validkills);
+               }
+               it.mmm_validkills = 0;
+               // player survived the round
+               if(IS_PLAYER(it) && !IS_DEAD(it)) // LegendGuard adds something for Karma 21-02-2021
+               {
+                       if((autocvar_g_mmm_reward_civilian && timed_out && it.mmm_status == MMM_STATUS_CIVILIAN) 
+                       || (autocvar_g_mmm_reward_civilian && !timed_out && it.mmm_status == MMM_STATUS_CIVILIAN))
+                       {
+                               karmaWinDifference(it);
+                               //PrintToChatAll(sprintf("^2REWARD ^7it.karmapoints: ^1%f", it.karmapoints));
+                               karma_Control(it);
+                       }
+
+                       //Sleuth reward after investigated a corpse
+                       if((autocvar_g_mmm_reward_sleuth && timed_out && it.mmm_status == MMM_STATUS_SLEUTH) 
+                       || (autocvar_g_mmm_reward_sleuth && !timed_out && it.mmm_status == MMM_STATUS_SLEUTH))
+                       {
+                               if (it.investigated == true)
+                               {
+                                       karmaWinDifference(it);
+                                       it.investigated = false;
+                               }
+                               karma_Control(it);
+                       }
+
+                       if(it.mmm_status == MMM_STATUS_CIVILIAN)
+                       {
+                               karmaWinDifference(it);
+                               //PrintToChatAll(sprintf("^2CIVILIAN ^7it.karmapoints: ^1%f", it.karmapoints));
+                               karma_Control(it);
+                       }
+                       else if(it.mmm_status == MMM_STATUS_MURDERER)
+                       {
+                               karmaWinDifference(it);
+                               //PrintToChatAll(sprintf("^1MURDERER ^7it.karmapoints: ^1%f", it.karmapoints));
+                               karma_Control(it);
+                       }
+               }
+       });
+}
+
+float mmm_CheckWinner()
+{
+       if(round_handler_GetEndTime() > 0 && round_handler_GetEndTime() - time <= 0)
+       {
+               // if the match times out, civilians win too!
+               Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_MMM_CIVILIAN_WIN);
+               Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_MMM_CIVILIAN_WIN);
+               FOREACH_CLIENT(true,
+               {
+                       if(IS_PLAYER(it))
+                               nades_Clear(it);
+                       mmm_FakeTimeLimit(it, -1);
+               });
+
+               mmm_UpdateScores(true);
+
+               allowed_to_spawn = false;
+               game_stopped = true;
+               round_handler_Init(5, autocvar_g_mmm_warmup, autocvar_g_mmm_round_timelimit);
+               return 1;
+       }
+
+       int civilian_count = 0, murderer_count = 0, sleuth_count = 0;
+       FOREACH_CLIENT(IS_PLAYER(it) && !IS_DEAD(it),
+       {
+               if(it.mmm_status == MMM_STATUS_CIVILIAN)
+                       civilian_count++;
+               else if(it.mmm_status == MMM_STATUS_MURDERER)
+                       murderer_count++;
+               else if(it.mmm_status == MMM_STATUS_SLEUTH) //LegendGuard adds sleuth_count 20-02-2021 
+                       sleuth_count++;
+       });
+       if(civilian_count > 0 && murderer_count > 0)
+       {
+               return 0;
+       }
+
+       if(murderer_count > 0) // murderers win
+       {
+               Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_MMM_MURDERER_WIN);
+               Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_MMM_MURDERER_WIN);
+       }
+       else if(civilian_count > 0) // civilians win
+       {
+               Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_MMM_CIVILIAN_WIN);
+               Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_MMM_CIVILIAN_WIN);
+       }
+       else if (sleuth_count > 0 && civilian_count > 0) // sleuths are same as civilians win
+       {
+               Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_MMM_CIVILIAN_WIN);
+               Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_MMM_CIVILIAN_WIN);
+       }
+       else
+       {
+               Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_ROUND_TIED);
+               Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_ROUND_TIED);
+       }
+
+       mmm_UpdateScores(false);
+
+       allowed_to_spawn = false;
+       game_stopped = true;
+       round_handler_Init(5, autocvar_g_mmm_warmup, autocvar_g_mmm_round_timelimit);
+
+       FOREACH_CLIENT(true,
+       {
+               if(IS_PLAYER(it))
+               {
+                       it.respawn_flags = RESPAWN_SILENT; //CSQC print output respawn lib.qh error fix
+                       nades_Clear(it);
+               }
+               mmm_FakeTimeLimit(it, -1);
+       });
+
+       return 1;
+}
+
+void mmm_RoundStart()
+{
+       allowed_to_spawn = boolean(warmup_stage);
+       int playercount = 0;
+       
+       FOREACH_CLIENT(true,
+       {
+               if(IS_PLAYER(it) && !IS_DEAD(it))
+               {
+                       ++playercount;
+                       it.mmm_status = MMM_STATUS_CIVILIAN;
+               }
+               else
+                       it.mmm_status = 0; // this is mostly a safety check; if a client manages to somehow maintain a mmm status, clear it before the round starts!
+               it.mmm_validkills = 0;
+       });
+       
+       int civilian_count = bound(1, ((autocvar_g_mmm_civilian_count >= 1) ? autocvar_g_mmm_civilian_count : floor(playercount * autocvar_g_mmm_civilian_count)), playercount - 1); // 20%, but ensure at least 1 and less than total
+       int total_civilians = 0;
+       //int murderer_count = bound(1, ((autocvar_g_mmm_murderer_count >= 1) ? autocvar_g_mmm_murderer_count : floor(playercount * autocvar_g_mmm_murderer_count)), playercount - 1); // 20%, but ensure at least 1 and less than total
+       int total_murderers = 0;
+       //int sleuth_count = bound(1, ((autocvar_g_mmm_sleuth_count >= 1) ? autocvar_g_mmm_sleuth_count : floor(playercount * autocvar_g_mmm_sleuth_count)), playercount - 1); // 20%, but ensure at least 1 and less than total
+       int total_sleuths = 0;
+
+       //civilians TOTAL
+       FOREACH_CLIENT_RANDOM(IS_PLAYER(it) && !IS_DEAD(it),
+       {
+               if(total_civilians >= civilian_count)
+                       break;
+               //LegendGuard fixes the round start again 22-03-2021
+               total_civilians++;
+               if (total_civilians <= 1)
+               {
+                       if (total_murderers <= 1)
+                       {
+                               total_murderers++;
+                               it.mmm_status = MMM_STATUS_MURDERER;
+                       }
+               }
+               else if (total_civilians == 2)
+               {
+                       if (total_sleuths >= 1)
+                               break;
+                       else
+                       {
+                               total_sleuths++;
+                               it.mmm_status = MMM_STATUS_SLEUTH;
+                       }
+               }
+               else if (total_civilians == 5)
+               {
+                       if (total_sleuths >= 2)
+                               break;
+                       else
+                       {
+                               total_sleuths++;
+                               it.mmm_status = MMM_STATUS_SLEUTH;
+                       }
+               }
+               else if (total_civilians >= 7)
+               {
+                       if (total_sleuths >= 3)
+                               break;
+                       else if (total_murderers == 3)
+                       {
+                               total_murderers++;
+                               it.mmm_status = MMM_STATUS_MURDERER;
+                       }
+                       else
+                       {
+                               total_sleuths++;
+                               it.mmm_status = MMM_STATUS_SLEUTH;
+                       }
+               }
+               else
+               {
+                       total_murderers++; 
+                       it.mmm_status = MMM_STATUS_MURDERER;
+               }
+       });
+
+       FOREACH_CLIENT(IS_PLAYER(it) && !IS_DEAD(it),
+       {
+               float totalmeankarma = ((autocvar_g_mmm_max_karma_points + autocvar_g_mmm_min_karma_points + it.karmapoints) / 3);
+               karma_Control(it);
+               it.activekillerrole = false;
+
+               if(it.mmm_status == MMM_STATUS_CIVILIAN)
+               {
+                       SetResource(it, RES_SHELLS, 10);
+                       SetResource(it, RES_BULLETS, 20);
+                       SetResource(it, RES_ROCKETS, 10);
+                       SetResource(it, RES_CELLS, 10);
+                       if (it.karmapoints <= totalmeankarma)
+                       {
+                               centerprint(it, strcat(BOLD_OPERATOR, "^1KARMA WARNING!\n^3Here, have the Rifle!"));
+                               GiveWeapon(it, WEP_RIFLE.m_id, OP_PLUS, 1);
+                       }
+                       //Gives Mine Layer weapon to the player
+                       GiveWeapon(it, WEP_MINE_LAYER.m_id, OP_PLUS, 1);
+                       Send_Notification(NOTIF_ONE_ONLY, it, MSG_CENTER, CENTER_MMM_CIVILIAN);
+                       Send_Notification(NOTIF_ONE_ONLY, it, MSG_INFO, INFO_MMM_CIVILIAN);
+                       //PrintToChatAll(sprintf("^1DEBUG^7: %s is ^2Civilian^7!", it.netname));
+               }
+               else if(it.mmm_status == MMM_STATUS_MURDERER)
+               {
+                       SetResource(it, RES_SHELLS, 10);
+                       SetResource(it, RES_BULLETS, 20);
+                       SetResource(it, RES_ROCKETS, 10);
+                       SetResource(it, RES_CELLS, 10);
+                       if (it.karmapoints <= totalmeankarma)
+                       {
+                               centerprint(it, strcat(BOLD_OPERATOR, "^1KARMA WARNING!\n^3Here, have the Rifle!"));
+                               GiveWeapon(it, WEP_RIFLE.m_id, OP_PLUS, 1);
+                       }
+                       //Gives Mine Layer weapon to the player
+                       GiveWeapon(it, WEP_MINE_LAYER.m_id, OP_PLUS, 1);
+                       Send_Notification(NOTIF_ONE_ONLY, it, MSG_CENTER, CENTER_MMM_MURDERER);
+                       Send_Notification(NOTIF_ONE_ONLY, it, MSG_INFO, INFO_MMM_MURDERER);
+                       //PrintToChatAll(sprintf("^1DEBUG^7: %s is ^1Murderer^7!", it.netname));
+               }
+               else if(it.mmm_status == MMM_STATUS_SLEUTH)
+               {
+                       SetResource(it, RES_ROCKETS, 10);
+                       if (it.karmapoints <= totalmeankarma)
+                       {
+                               centerprint(it, strcat(BOLD_OPERATOR, "^1KARMA WARNING!\n^3Here, have the Rifle!"));
+                               GiveWeapon(it, WEP_RIFLE.m_id, OP_PLUS, 1);
+                       }
+                       //Gives Shockwave and Mine Layer weapon to the player
+                       GiveWeapon(it, WEP_SHOCKWAVE.m_id, OP_PLUS, 1);
+                       GiveWeapon(it, WEP_MINE_LAYER.m_id, OP_PLUS, 1);
+                       Send_Notification(NOTIF_ONE_ONLY, it, MSG_CENTER, CENTER_MMM_SLEUTH);
+                       Send_Notification(NOTIF_ONE_ONLY, it, MSG_INFO, INFO_MMM_SLEUTH);
+                       PrintToChatAll(sprintf("%s is ^4Sleuth^7!", it.netname));
+               }
+               mmm_FakeTimeLimit(it, round_handler_GetEndTime());
+       });
+}
+
+bool mmm_CheckPlayers()
+{
+       static int prev_missing_players;
+       allowed_to_spawn = true;
+       int playercount = 0;
+
+       FOREACH_CLIENT(IS_PLAYER(it) && !IS_DEAD(it),
+       {       
+               //PrintToChatAll(sprintf("it.karmapoints ^5begin: ^3%f",it.karmapoints));
+               //Karma points start
+               if (it.karmastarted != true)
+               {
+                       GameRules_scoring_add(it, MMM_KARMA, autocvar_g_mmm_max_karma_points - it.karmapoints);
+                       it.karmapoints = autocvar_g_mmm_max_karma_points;
+                       it.karmastarted = true;
+               }
+               karma_Control(it);
+               ++playercount;
+               //PrintToChatAll(sprintf("it.karmapoints ^6end: ^3%f",it.karmapoints));
+       });
+
+       if (playercount >= 2)
+       {
+               if(prev_missing_players > 0)
+                       Kill_Notification(NOTIF_ALL, NULL, MSG_CENTER, CPID_MISSING_PLAYERS);
+               prev_missing_players = -1;
+               return true;
+       }
+
+       if(playercount == 0)
+       {
+               if(prev_missing_players > 0)
+                       Kill_Notification(NOTIF_ALL, NULL, MSG_CENTER, CPID_MISSING_PLAYERS);
+               prev_missing_players = -1;
+               return false;
+       }
+
+       // if we get here, only 1 player is missing
+       if(prev_missing_players != 1)
+       {
+               Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_MISSING_PLAYERS, 1);
+               prev_missing_players = 1;
+       }
+       return false;
+}
+
+bool mmm_isEliminated(entity e)
+{
+       if(e.caplayer == 1 && (IS_DEAD(e) || e.frags == FRAGS_PLAYER_OUT_OF_GAME))
+               return true;
+       if(e.caplayer == 0.5)
+               return true;
+       return false;
+}
+
+void mmm_Initialize() // run at the start of a match, initiates game mode
+{
+       GameRules_scoring(0, SFL_SORT_PRIO_PRIMARY, 0, {
+               field(SP_MMM_KARMA, "karma", SFL_SORT_PRIO_SECONDARY); //LegendGuard adds Karma points in the scoreboard 22-02-2021
+       });
+
+       allowed_to_spawn = true;
+       round_handler_Spawn(mmm_CheckPlayers, mmm_CheckWinner, mmm_RoundStart);
+       round_handler_Init(5, autocvar_g_mmm_warmup, autocvar_g_mmm_round_timelimit);
+       EliminatedPlayers_Init(mmm_isEliminated);
+}
+
+void checkWeaponDeathtype(entity target, float deathtype)
+{
+       switch (deathtype)
+       {
+               case WEP_ARC.m_id: case 276: case 788: target.killedwithweapon = "Impacted by the Arc's electric shock"; return;
+               case WEP_BLASTER.m_id: case 513: target.killedwithweapon = "Blasted by the Blaster"; return;
+               case WEP_CRYLINK.m_id: case 263: case 519: target.killedwithweapon = "Shot by the Crylink"; return;
+               case WEP_DEVASTATOR.m_id: case 522: case 1546: target.killedwithweapon = "Bombarded by the Devastator"; return;
+               case WEP_ELECTRO.m_id: case 262: case 518: case 1542: target.killedwithweapon = "Electrocuted by the Electro"; return;
+               case WEP_FIREBALL.m_id: case 273: case 529: case 1297: target.killedwithweapon = "Burned by the Fireball"; return;
+               case WEP_HAGAR.m_id: case 265: target.killedwithweapon = "Gunned by the Hagar"; return;
+               case WEP_HLAC.m_id: case 270: case 526: target.killedwithweapon = "Cut down with the HLAC"; return;
+               case WEP_HOOK.m_id: case 1805: target.killedwithweapon = "Caught in Hook gravity bomb"; return;
+               case WEP_MACHINEGUN.m_id: target.activekillerrole = true; target.killedwithweapon = "Riddled full of holes by the Machine Gun"; return;
+               case WEP_MINE_LAYER.m_id: case 517: case 1541: target.killedwithweapon = "Exploited by the Mine Layer"; return;
+               case WEP_MORTAR.m_id: case 516: case 1284: target.killedwithweapon = "Blew up with the Mortar"; return;
+               case WEP_OVERKILL_NEX.m_id: target.killedwithweapon = "Sniped by the Overkill Nex"; return;
+               case WEP_RIFLE.m_id: case 272: target.activekillerrole = true; target.killedwithweapon = "Sniped by the Rifle"; return;
+               case WEP_SEEKER.m_id: case 274: case 786: target.killedwithweapon = "Blasted by the Seeker"; return;
+               case WEP_SHOCKWAVE.m_id: target.killedwithweapon = "Gunned down by the Shockwave"; return;
+               case 275: target.killedwithweapon = "Knocked by the Shockwave"; return;
+               case WEP_SHOTGUN.m_id: target.activekillerrole = true; target.killedwithweapon = "Shot by Shotgun"; return;
+               case 258: target.killedwithweapon = "Knocked by the Shotgun"; return;
+               case WEP_TUBA.m_id: target.killedwithweapon = "Ear pain by the @!#%'n Tuba"; return;
+               case WEP_VAPORIZER.m_id: case 257: case 769: target.killedwithweapon = "Sniped by the Vaporizer"; return;
+               case WEP_VORTEX.m_id: target.killedwithweapon = "Sniped by the Vortex"; return;
+               case DEATH_FALL.m_id: target.killedwithweapon = "Fall"; return;
+               case DEATH_FIRE.m_id: target.killedwithweapon = "Burned with the fire"; return;
+               case DEATH_LAVA.m_id: target.killedwithweapon = "Burned in lava"; return;
+               case DEATH_MIRRORDAMAGE.m_id: target.killedwithweapon = "Suicide"; return;
+               case DEATH_SLIME.m_id: target.killedwithweapon = "Melted in slime"; return;
+               case DEATH_TELEFRAG.m_id: target.killedwithweapon = "Telefragged"; return;
+               case DEATH_NADE.m_id: target.killedwithweapon = "Blown up by the nade"; return;
+               case DEATH_NADE_NAPALM.m_id: target.killedwithweapon = "Burned by the Napalm nade"; return;
+               case DEATH_NADE_ICE.m_id: target.killedwithweapon = "Frozen by the Ice nade"; return;
+               case DEATH_NADE_HEAL.m_id: target.killedwithweapon = "Sucked by the Heal nade"; return;
+               default: target.killedwithweapon = "Unknown"; return;
+       }
+}
+
+void ReduceKarmaPointsandFrags(entity frag_attacker, entity frag_target, float frag_deathtype, entity wep_ent)
+{
+       karmaLoseDifference(frag_attacker, frag_target);
+       GiveFrags(frag_attacker, frag_target, ((autocvar_g_mmm_punish_teamkill) ? -1 : -2), frag_deathtype, wep_ent.weaponentity_fld);
+       karma_Control(frag_attacker);
+       frag_target.whokilled = frag_attacker.netname;
+}
+
+// ==============
+// Hook Functions
+// ==============
+
+MUTATOR_HOOKFUNCTION(mmm, ClientObituary)
+{
+       // LegendGuard's IDEA: To adjust the grade of severity of karma, 
+       // we could add if sentence per weapons and adjust each weapon attack
+       // its own grade. Instead doing random decrease grade 22-02-2021
+       
+       // in mmm, announcing a frag would tell everyone who the murderer is
+       entity frag_attacker = M_ARGV(1, entity);
+       entity frag_target = M_ARGV(2, entity);
+       
+       if(IS_PLAYER(frag_attacker) && frag_attacker != frag_target)
+       {
+               float frag_deathtype = M_ARGV(3, float);
+               entity wep_ent = M_ARGV(4, entity);
+               
+               //PrintToChatAll(strcat("deathtype var: ", ftos(frag_deathtype)));
+               checkWeaponDeathtype(frag_target, frag_deathtype);
+               // "team" kill, a point is awarded to the player by default so we must take it away plus an extra one
+               // unless the player is going to be punished for suicide, in which case just remove one
+               if(frag_attacker.mmm_status == frag_target.mmm_status)
+               {
+                       //PrintToChatAll("^1DEBUG^7: A ^2PLAYER^7 has fragged a ^2PLAYER OF HIS OWN TEAM^7, TOO BAD!");
+                       ReduceKarmaPointsandFrags(frag_attacker, frag_target, frag_deathtype, wep_ent);
+                       switch (frag_attacker.mmm_status)
+                       {
+                               case MMM_STATUS_CIVILIAN: frag_target.killerrole = "\n^3Killer role: ^2Civilian"; return;
+                               case MMM_STATUS_MURDERER: frag_target.killerrole = "\n^3Killer role: ^1Murderer"; return;
+                               case MMM_STATUS_SLEUTH: frag_target.killerrole = "\n^3Killer role: ^4Sleuth"; return;
+                               default: return;
+                       }
+                       //PrintToChatAll(sprintf("frag_attacker.karmapoints: ^1%f", frag_attacker.karmapoints));
+               }
+
+               if(frag_attacker.mmm_status == MMM_STATUS_SLEUTH)
+               {
+                       if (frag_target.mmm_status == MMM_STATUS_CIVILIAN || frag_target.mmm_status == MMM_STATUS_SLEUTH)
+                       {       
+                               //PrintToChatAll("^1DEBUG^7: A ^4Sleuth^7 fragged an ^2Civilian^7/^4Sleuth^7, TOO BAD!");
+                               ReduceKarmaPointsandFrags(frag_attacker, frag_target, frag_deathtype, wep_ent);
+                               frag_target.killerrole = "\n^3Killer role: ^4Sleuth";
+                               //PrintToChatAll(sprintf("frag_attacker.karmapoints: ^1%f", frag_attacker.karmapoints));
+                       }
+                       else
+                       {
+                               frag_target.whokilled = frag_attacker.netname;
+                               frag_target.killerrole = "\n^3Killer role: ^4Sleuth";
+                       }
+               }
+
+               if (frag_attacker.mmm_status == MMM_STATUS_CIVILIAN)
+               {
+                       if (frag_target.mmm_status == MMM_STATUS_SLEUTH)
+                       {
+                               //PrintToChatAll("^1DEBUG^7: An ^2Civilian^7 fragged a ^4Sleuth^7, TOO BAD!");
+                               ReduceKarmaPointsandFrags(frag_attacker, frag_target, frag_deathtype, wep_ent);
+                               frag_target.killerrole = "\n^3Killer role: ^2Civilian";
+                       }
+                       else
+                       {
+                               frag_target.whokilled = frag_attacker.netname;
+                               frag_target.killerrole = "\n^3Killer role: ^2Civilian";
+                       }
+               }
+               
+               if (frag_attacker.mmm_status == MMM_STATUS_MURDERER)
+               {
+                       if (frag_target.mmm_status == MMM_STATUS_CIVILIAN)
+                       {
+                               frag_target.whokilled = frag_attacker.netname;
+                               frag_target.killerrole = "\n^3Killer role: ^1Murderer";
+                       }
+                       else
+                       {
+                               frag_target.whokilled = frag_attacker.netname;
+                               frag_target.killerrole = "\n^3Killer role: ^1Murderer";
+                       }
+               }
+               //if mmm_status is 1, means civilian, 2 means murderer, 3 means sleuth, TODO: the bots: frag_attacker(1) shouldn't attack to frag_target(3)
+               //PrintToChatAll(sprintf("^1DEBUG^7: frag_attacker.mmm_status is ^3%s^7",ftos(frag_attacker.mmm_status)));
+               //PrintToChatAll(sprintf("^1DEBUG^7: frag_target.mmm_status is ^3%s^7",ftos(frag_target.mmm_status)));
+       }
+       else
+       {
+               float frag_deathtype = M_ARGV(3, float);
+               checkWeaponDeathtype(frag_target, frag_deathtype);
+       }
+
+       //TODO: try to do a "find out" if a sleuth can see who fragged to who if possible 21-02-2021
+       M_ARGV(5, bool) = true; // anonymous attacker
+}
+
+//karma weapon damage, halve the damage attack when player has low karma 20-03-2021
+MUTATOR_HOOKFUNCTION(mmm, Damage_Calculate)
+{
+       entity attacker = M_ARGV(1, entity);
+       entity target = M_ARGV(2, entity);
+       float deathtype = M_ARGV(3, float);
+       float damage = M_ARGV(4, float);
+       vector force = M_ARGV(6, vector);
+       string corpsemessagestrcat = "";
+
+       if (autocvar_g_mmm_karma_damageactive != false)
+       {
+               if (IS_PLAYER(attacker))
+               {
+                       if(target == attacker) // damage done to yourself
+                       {
+                               damage /= autocvar_g_weapondamagefactor / (attacker.karmapoints / autocvar_g_mmm_max_karma_points);
+                               force /= autocvar_g_weaponforcefactor / (attacker.karmapoints / autocvar_g_mmm_max_karma_points);
+                       }
+                       else if (target != attacker)
+                       {
+                               damage /= autocvar_g_weapondamagefactor / (attacker.karmapoints / autocvar_g_mmm_max_karma_points);
+                               force /= autocvar_g_weaponforcefactor / (attacker.karmapoints / autocvar_g_mmm_max_karma_points);
+                       }
+                       else
+                       {
+                               damage *= autocvar_g_weapondamagefactor;
+                               force *= autocvar_g_weaponforcefactor;
+                       }
+               }
+       }
+
+       //SLEUTH CORPSE DETECTION SKILL 21-03-2021
+       if (attacker.mmm_status == MMM_STATUS_SLEUTH)
+       {
+               if(IS_DEAD(target))
+               {
+                       //Shockwave weapon as radar gun to check the corpses 22-03-2021
+                       if(DEATH_ISWEAPON(deathtype, WEP_SHOCKWAVE))
+                       {
+                               if (target.killedwithweapon == "")
+                                       target.killedwithweapon = "UNKNOWN CAUSE";
+                               
+                               if (target.activekillerrole != true)
+                               {
+                                       target.killerrole = "";
+                                       target.activekillerrole = false;
+                               }
+
+                               string killedbyphrase = strcat("\n^3Killed by:^7 ", target.whokilled, target.killerrole); 
+                               string wepkilledphrase = strcat("\n^3Cause:^7 ", target.killedwithweapon);
+                               if (target.whokilled == "")
+                               {
+                                       killedbyphrase = "";
+                                       if (target.killedwithweapon == "")
+                                               wepkilledphrase = "\n^3Cause:^7 UNKNOWN CAUSE";
+                               }
+
+                               damage = 0;
+                               force = '0 0 0';
+                               if (target.mmm_status == MMM_STATUS_CIVILIAN)
+                               {
+                                       //try to add centerprint message for chat privately if possible
+                                       corpsemessagestrcat = strcat("\n^3Name:^7 ", target.netname, "\n^3Role: ^2Civilian", killedbyphrase, wepkilledphrase);
+                                       centerprint(attacker, strcat(BOLD_OPERATOR, corpsemessagestrcat));//("\n^6Name^3:^7 ", target.netname, "\n^5Role^3: ^2Civilian\n", "^1Killed by^3:^7 ", target.whokilled)));
+                               }
+                               else if (target.mmm_status == MMM_STATUS_MURDERER)
+                               {
+                                       corpsemessagestrcat = strcat("\n^3Name:^7 ", target.netname, "\n^3Role: ^1Murderer", killedbyphrase, wepkilledphrase);
+                                       centerprint(attacker, strcat(BOLD_OPERATOR, corpsemessagestrcat));//("\n^6Name^3:^7 ", target.netname, "\n^5Role^3: ^1Murderer\n", "^1Killed by^3:^7 ", target.whokilled)));
+                               }
+                               else if (target.mmm_status == MMM_STATUS_SLEUTH)
+                               {
+                                       corpsemessagestrcat = strcat("\n^3Name:^7 ", target.netname, "\n^3Role: ^4Sleuth", killedbyphrase, wepkilledphrase);
+                                       centerprint(attacker, strcat(BOLD_OPERATOR, corpsemessagestrcat));//("\n^6Name^3:^7 ", target.netname, "\n^5Role^3: ^4Sleuth\n", "^1Killed by^3:^7 ", target.whokilled)));
+                               }
+                               attacker.investigated = true;
+                       }
+               }
+       }
+
+       M_ARGV(4, float) = damage;
+       M_ARGV(6, vector) = force;
+}
+
+MUTATOR_HOOKFUNCTION(mmm, PlayerPreThink)
+{
+       entity player = M_ARGV(0, entity);
+       
+       if(IS_PLAYER(player) || player.caplayer)
+       {
+               // update the scoreboard colour display to out the real killer at the end of the round
+               // running this every frame to avoid cheats
+               int plcolor = MMM_COLOR_CIVILIAN;
+               if(player.mmm_status == MMM_STATUS_CIVILIAN && game_stopped) //Civilian status by default
+                       plcolor = MMM_COLOR_CIVILIAN;
+               if(player.mmm_status == MMM_STATUS_MURDERER && game_stopped)
+                       plcolor = MMM_COLOR_MURDERER;
+               //LegendGuard adds for Sleuth 21-02-2021
+               if(player.mmm_status == MMM_STATUS_SLEUTH)// && game_stopped)
+                       plcolor = MMM_COLOR_SLEUTH;
+               setcolor(player, plcolor);
+       }
+
+       //CORPSE FEATURE 10-03-2021
+       if (IS_DEAD(player))
+       {
+               player.event_damage = func_null;
+               //player.health = 0;
+               player.solid = SOLID_CORPSE;
+               set_movetype(player, MOVETYPE_STEP); //test with MOVETYPE_TOSS or MOVETYPE_WALK (it's like sliding object) or MOVETYPE_BOUNCE (maybe not good)
+       }
+}
+
+MUTATOR_HOOKFUNCTION(mmm, PlayerSpawn)
+{
+       entity player = M_ARGV(0, entity);
+
+       player.mmm_status = 0;
+       player.mmm_validkills = 0;
+       player.caplayer = 1;
+       if (!warmup_stage)
+               eliminatedPlayers.SendFlags |= 1;
+}
+
+MUTATOR_HOOKFUNCTION(mmm, ForbidSpawn)
+{
+       entity player = M_ARGV(0, entity);
+
+       // spectators / observers that weren't playing can join; they are
+       // immediately forced to observe in the PutClientInServer hook
+       // this way they are put in a team and can play in the next round
+       if (!allowed_to_spawn && player.caplayer)
+               return true;
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(mmm, PutClientInServer)
+{
+       entity player = M_ARGV(0, entity);
+
+       if (!allowed_to_spawn && IS_PLAYER(player)) // this is true even when player is trying to join
+       {
+               TRANSMUTE(Observer, player);
+               if (CS(player).jointime != time && !player.caplayer) // not when connecting
+               {
+                       player.caplayer = 0.5;
+                       Send_Notification(NOTIF_ONE_ONLY, player, MSG_INFO, INFO_CA_JOIN_LATE);
+               }
+       }
+}
+
+MUTATOR_HOOKFUNCTION(mmm, reset_map_players)
+{
+       FOREACH_CLIENT(true, {
+               CS(it).killcount = 0;
+               it.mmm_status = 0;
+               mmm_FakeTimeLimit(it, -1); // restore original timelimit
+               if (!it.caplayer && IS_BOT_CLIENT(it))
+                       it.caplayer = 1;
+               if (it.caplayer)
+               {
+                       TRANSMUTE(Player, it);
+                       it.caplayer = 1;
+                       it.respawn_flags = RESPAWN_SILENT; //CSQC print output respawn lib.qh error fix
+                       PutClientInServer(it);
+               }
+       });
+       bot_relinkplayerlist();
+       return true;
+}
+
+MUTATOR_HOOKFUNCTION(mmm, reset_map_global)
+{
+       allowed_to_spawn = true;
+       return true;
+}
+
+entity mmm_LastPlayerForTeam(entity this)
+{
+       entity last_pl = NULL;
+       FOREACH_CLIENT(IS_PLAYER(it) && it != this, {
+               if (!IS_DEAD(it) && this.mmm_status == it.mmm_status)
+               {
+                       if (!last_pl)
+                       {
+                               last_pl = it;
+                       }
+                       else
+                               return NULL;
+               }
+       });
+       return last_pl;
+}
+
+void mmm_LastPlayerForTeam_Notify(entity this)
+{
+       if (!warmup_stage && round_handler_IsActive() && round_handler_IsRoundStarted())
+       {
+               entity pl = mmm_LastPlayerForTeam(this);
+               if (pl)
+                       Send_Notification(NOTIF_ONE_ONLY, pl, MSG_CENTER, CENTER_ALONE);
+       }
+}
+
+MUTATOR_HOOKFUNCTION(mmm, PlayerDies)
+{
+       entity frag_attacker = M_ARGV(1, entity);
+       entity frag_target = M_ARGV(2, entity);
+       //float frag_deathtype = M_ARGV(3, float);
+
+       mmm_LastPlayerForTeam_Notify(frag_target);
+       if (!allowed_to_spawn)
+       {
+               frag_target.respawn_flags = RESPAWN_DENY;
+               // prevent unwanted sudden rejoin as spectator and movement of spectator camera
+               frag_target.respawn_time = time + 2;
+       }
+       frag_target.respawn_flags |= RESPAWN_DENY;
+       frag_target.event_damage = func_null;
+       frag_target.health = 0;
+       
+       if (!warmup_stage)
+       {
+               eliminatedPlayers.SendFlags |= 1;
+               if (IS_BOT_CLIENT(frag_target))
+                       bot_clear(frag_target);
+       }
+       
+       //if(frag_attacker.mmm_status == frag_target.mmm_status)
+       // killed an ally! punishment is sentenced
+       if(frag_attacker.mmm_status == MMM_STATUS_SLEUTH)
+       {
+               if (frag_target.mmm_status == MMM_STATUS_CIVILIAN)
+               {
+                       //PrintToChatAll("^1DEBUG^7: ^4SLEUTH ^1DAMAGE/DEAD^7 HAS TAKEN!");
+                       //30 damage points deal
+                       Damage(frag_attacker, frag_attacker, frag_attacker, 30, DEATH_MIRRORDAMAGE.m_id, DMG_NOWEP, frag_attacker.origin, '0 0 0');
+               }
+       }
+       if (frag_attacker.mmm_status == MMM_STATUS_CIVILIAN)
+       {
+               if (frag_target.mmm_status == MMM_STATUS_SLEUTH)
+               {
+                       //PrintToChatAll("^1DEBUG^7: ^2CIVILIAN ^1DAMAGE/DEAD^7 HAS TAKEN!");
+                       //30 damage points deal
+                       Damage(frag_attacker, frag_attacker, frag_attacker, 30, DEATH_MIRRORDAMAGE.m_id, DMG_NOWEP, frag_attacker.origin, '0 0 0');
+               }
+       }
+       return true;
+}
+
+MUTATOR_HOOKFUNCTION(mmm, ClientDisconnect)
+{
+       entity player = M_ARGV(0, entity);
+
+       if (IS_PLAYER(player) && !IS_DEAD(player))
+               mmm_LastPlayerForTeam_Notify(player);
+       return true;
+}
+
+MUTATOR_HOOKFUNCTION(mmm, MakePlayerObserver)
+{
+       // LegendGuard, here is where spectators shouldn't talk to any players to say the hints or who is who 21-10-2021
+       entity player = M_ARGV(0, entity);
+
+       if (IS_PLAYER(player) && !IS_DEAD(player))
+               mmm_LastPlayerForTeam_Notify(player);
+       if (player.killindicator_teamchange == -2) // player wants to spectate
+               player.caplayer = 0;
+       if (player.caplayer)
+               player.frags = FRAGS_PLAYER_OUT_OF_GAME;
+       if (!warmup_stage)
+               eliminatedPlayers.SendFlags |= 1;
+       if (!player.caplayer)
+       {
+               player.mmm_validkills = 0;
+               player.mmm_status = 0;
+               mmm_FakeTimeLimit(player, -1); // restore original timelimit
+               return false;  // allow team reset
+       }
+       return true;  // prevent team reset
+}
+
+MUTATOR_HOOKFUNCTION(mmm, Scores_CountFragsRemaining)
+{
+       // announce remaining frags?
+       return true;
+}
+
+MUTATOR_HOOKFUNCTION(mmm, GiveFragsForKill, CBC_ORDER_FIRST)
+{
+       entity frag_attacker = M_ARGV(0, entity);
+       if(!warmup_stage && round_handler_IsActive() && round_handler_IsRoundStarted())
+               frag_attacker.mmm_validkills += M_ARGV(2, float);
+       M_ARGV(2, float) = 0; // score will be given to the winner when the round ends
+       return true;
+}
+
+MUTATOR_HOOKFUNCTION(mmm, AddPlayerScore)
+{
+       // add scorefield for scoreboard here
+       entity scorefield = M_ARGV(0, entity);
+       if(scorefield == SP_KILLS || scorefield == SP_DEATHS || scorefield == SP_SUICIDES || scorefield == SP_DMG || scorefield == SP_DMGTAKEN)
+               M_ARGV(1, float) = 0; // don't report that the player has killed or been killed, that would out them as a murderer!
+}
+
+MUTATOR_HOOKFUNCTION(mmm, CalculateRespawnTime)
+{
+       // no respawn calculations needed, player is forced to spectate anyway
+       return true;
+}
+
+MUTATOR_HOOKFUNCTION(mmm, Bot_FixCount, CBC_ORDER_EXCLUSIVE)
+{
+       FOREACH_CLIENT(IS_REAL_CLIENT(it), {
+               if (IS_PLAYER(it) || it.caplayer == 1)
+                       ++M_ARGV(0, int);
+               ++M_ARGV(1, int);
+       });
+       return true;
+}
+
+MUTATOR_HOOKFUNCTION(mmm, ClientCommand_Spectate)
+{
+       entity player = M_ARGV(0, entity);
+
+       if (player.caplayer)
+       {
+               // they're going to spec, we can do other checks
+               if (autocvar_sv_spectate && (IS_SPEC(player) || IS_OBSERVER(player)))
+                       Send_Notification(NOTIF_ONE_ONLY, player, MSG_INFO, INFO_CA_LEAVE);
+               return MUT_SPECCMD_FORCE;
+       }
+
+       return MUT_SPECCMD_CONTINUE;
+}
+
+MUTATOR_HOOKFUNCTION(mmm, GetPlayerStatus)
+{
+       entity player = M_ARGV(0, entity);
+
+       return player.caplayer == 1;
+}
+
+MUTATOR_HOOKFUNCTION(mmm, BotShouldAttack)
+{
+       entity bot = M_ARGV(0, entity);
+       entity targ = M_ARGV(1, entity);
+
+       if(targ.mmm_status == bot.mmm_status)
+       {
+               return true;
+       }
+       
+       // LegendGuard fixed the problem of Sleuths and Civilians attacking each other 26-03-2021
+       if(bot.mmm_status == MMM_STATUS_SLEUTH)
+       {
+               if(targ.mmm_status == MMM_STATUS_CIVILIAN)
+                       return true;
+       }
+}
diff --git a/qcsrc/common/gamemodes/gamemode/mmm/sv_mmm.qh b/qcsrc/common/gamemodes/gamemode/mmm/sv_mmm.qh
new file mode 100644 (file)
index 0000000..e5eca21
--- /dev/null
@@ -0,0 +1,24 @@
+#pragma once
+
+#include <common/mutators/base.qh>
+#include <common/scores.qh>
+void mmm_Initialize();
+
+REGISTER_MUTATOR(mmm, false)
+{
+    MUTATOR_STATIC();
+       MUTATOR_ONADD
+       {
+               mmm_Initialize();
+       }
+       return false;
+}
+
+.int mmm_validkills; // store the player's valid kills to be given at the end of the match (avoid exposing their score until then)
+.float karmapoints; //LegendGuard adds karma points to store player status 22-02-2021
+.string whokilled; //LegendGuard sets a variable to know who killed who 22-03-2021
+.string killerrole; //LegendGuard sets a variable to identify killer role 25-03-2021
+.string killedwithweapon; //LegendGuard sets a variable to know what cause provoked to the victim 23-03-2021
+.bool investigated; //LegendGuard sets a bool to make sure if detective investigated already a corpse once 24-03-2021
+.bool karmastarted; //LegendGuard fixes with a bool when round start for karma points
+.bool activekillerrole; //LegendGuard sets a variable to active killer role 25-03-2021
\ No newline at end of file
diff --git a/qcsrc/common/gamemodes/gamemode/ttt/_mod.inc b/qcsrc/common/gamemodes/gamemode/ttt/_mod.inc
deleted file mode 100644 (file)
index 5574f4a..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-// generated file; do not modify
-#include <common/gamemodes/gamemode/ttt/ttt.qc>
-#ifdef CSQC
-    #include <common/gamemodes/gamemode/ttt/cl_ttt.qc>
-#endif
-#ifdef SVQC
-    #include <common/gamemodes/gamemode/ttt/sv_ttt.qc>
-#endif
diff --git a/qcsrc/common/gamemodes/gamemode/ttt/_mod.qh b/qcsrc/common/gamemodes/gamemode/ttt/_mod.qh
deleted file mode 100644 (file)
index 09983d7..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-// generated file; do not modify
-#include <common/gamemodes/gamemode/ttt/ttt.qh>
-#ifdef CSQC
-    #include <common/gamemodes/gamemode/ttt/cl_ttt.qh>
-#endif
-#ifdef SVQC
-    #include <common/gamemodes/gamemode/ttt/sv_ttt.qh>
-#endif
diff --git a/qcsrc/common/gamemodes/gamemode/ttt/cl_ttt.qc b/qcsrc/common/gamemodes/gamemode/ttt/cl_ttt.qc
deleted file mode 100644 (file)
index 8820cf1..0000000
+++ /dev/null
@@ -1,103 +0,0 @@
-#include "cl_ttt.qh"
-
-#include <client/draw.qh>
-#include <client/hud/panel/modicons.qh>
-
-void HUD_Mod_TTT(vector pos, vector mySize)
-{
-       mod_active = 1; // ttt should always show the mod HUD
-
-       int mystatus = entcs_receiver(player_localnum).ttt_status;
-       string player_text = "";
-       vector player_color = '1 1 1';
-       //string player_icon = "";
-       if(mystatus == TTT_STATUS_TRAITOR)
-       {
-               player_text = _("Traitor");
-               player_color = '1 0 0';
-               //player_icon = "player_red";
-       }
-       else if(mystatus == TTT_STATUS_INNOCENT)
-       {
-               player_text = _("Innocent");
-               player_color = '0 1 0';
-               //player_icon = "player_neutral";
-       }
-       else if(mystatus == TTT_STATUS_DETECTIVE)
-       {
-               player_text = _("Detective");
-               player_color = '0 0 1';
-               //player_icon = "player_blue";
-       }
-       else
-       {
-               // if the player has no valid status, don't draw anything
-               return;
-       }
-
-       string time_text = string_null;
-       vector timer_color = '1 1 1';
-       if(!STAT(GAME_STOPPED) && !warmup_stage && STAT(TTT_ROUNDTIMER) > 0)
-       {
-               float timeleft = max(0, STAT(TTT_ROUNDTIMER) - time);
-               timeleft = ceil(timeleft);
-               float minutesLeft = floor(timeleft / 60);
-               time_text = seconds_tostring(timeleft);
-               if(intermission_time || minutesLeft >= 5 || warmup_stage || STAT(TTT_ROUNDTIMER) == 0)
-                       timer_color = '1 1 1'; //white
-               else if(minutesLeft >= 1)
-                       timer_color = '1 1 0'; //yellow
-               else
-                       timer_color = '1 0 0'; //red
-       }
-
-       //drawpic_aspect_skin(pos, player_icon, vec2(0.5 * mySize.x, mySize.y), '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
-       if(!time_text)
-               drawstring_aspect(pos, player_text, vec2(mySize.x, mySize.y), player_color, panel_fg_alpha, DRAWFLAG_NORMAL);
-       else
-       {
-               drawstring_aspect(pos, player_text, vec2(0.5 * mySize.x, mySize.y), player_color, panel_fg_alpha, DRAWFLAG_NORMAL);
-               drawstring_aspect(pos + eX * (0.5 * mySize.x), time_text, vec2(0.5 * mySize.x, mySize.y), timer_color, panel_fg_alpha, DRAWFLAG_NORMAL);
-       }
-}
-
-REGISTER_MUTATOR(cl_ttt, true);
-
-MUTATOR_HOOKFUNCTION(cl_ttt, ForcePlayercolors_Skip, CBC_ORDER_LAST)
-{
-       if(!ISGAMETYPE(TTT))
-               return false;
-               
-       entity player = M_ARGV(0, entity);
-       entity e = entcs_receiver(player.entnum - 1);
-       int otherplayer_status = ((e) ? e.ttt_status : 0);
-       int mystatus = entcs_receiver(player_localnum).ttt_status;
-
-       int plcolor = TTT_COLOR_INNOCENT; // default to innocent
-
-       if((mystatus == TTT_STATUS_TRAITOR || intermission || STAT(GAME_STOPPED)) && otherplayer_status == TTT_STATUS_TRAITOR)
-       {
-               plcolor = TTT_COLOR_TRAITOR;
-       }
-       
-       //LegendGuard adds INNOCENT part 21-02-2021
-       if((mystatus == TTT_STATUS_INNOCENT || intermission || STAT(GAME_STOPPED)) && otherplayer_status == TTT_STATUS_INNOCENT)
-       {
-               plcolor = TTT_COLOR_INNOCENT;
-       }
-
-       //LegendGuard adds if sentence for Detective model color which will shown for everyone 21-02-2021
-       if (otherplayer_status == TTT_STATUS_DETECTIVE)
-       {
-               plcolor = TTT_COLOR_DETECTIVE;
-       }
-
-       player.colormap = 1024 + plcolor;
-       return true;
-}
-
-MUTATOR_HOOKFUNCTION(cl_ttt, DrawScoreboard_Force)
-{
-       // show the scoreboard when the round ends, so players can see who the traitor was
-       return STAT(GAME_STOPPED);
-}
diff --git a/qcsrc/common/gamemodes/gamemode/ttt/cl_ttt.qh b/qcsrc/common/gamemodes/gamemode/ttt/cl_ttt.qh
deleted file mode 100644 (file)
index 508ddf2..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-#pragma once
-
-void HUD_Mod_TTT(vector pos, vector mySize);
diff --git a/qcsrc/common/gamemodes/gamemode/ttt/sv_ttt.qc b/qcsrc/common/gamemodes/gamemode/ttt/sv_ttt.qc
deleted file mode 100644 (file)
index 63c8e66..0000000
+++ /dev/null
@@ -1,942 +0,0 @@
-#include "sv_ttt.qh"
-
-//set g_ttt_detective_count 0.125 "number of players who will become detectives, set between 0 and 0.9 to use a multiplier of the current players, or 1 and above to specify an exact number of players"
-//float autocvar_g_ttt_detective_count = 0.125; //I don't think that it won't be used...
-float autocvar_g_ttt_innocent_count = 0.625;
-//float autocvar_g_ttt_traitor_count = 0.25;
-float autocvar_g_ttt_round_timelimit = 180;
-float autocvar_g_ttt_warmup = 10;
-bool autocvar_g_ttt_punish_teamkill = false;
-bool autocvar_g_ttt_reward_innocent = true;
-bool autocvar_g_ttt_reward_detective = true; //detective reward if investigated corpses
-float autocvar_g_ttt_max_karma_points = 1000; //LegendGuard sets Karma points 21-02-2021
-float autocvar_g_ttt_min_karma_points = 400;
-int autocvar_g_ttt_karma_bankick_tool = 0; //LegendGuard sets a ban tool for server admins 11-03-2021
-float autocvar_g_ttt_karma_bantime = 1800; //karma ban seconds
-bool autocvar_g_ttt_karma_damageactive = true; //LegendGuard sets Karma damage setting if active 20-03-2021
-
-// 27-02-2021
-// Ideas:
-// Add for the corpse a role of who killed 22-03-2021
-
-// Detective is a created team, this team is added inside Innocents team
-
-//TODO: 
-// detective shouldn't be attacked by innocent bots
-
-void ttt_FakeTimeLimit(entity e, float t)
-{
-       if(!IS_REAL_CLIENT(e))
-               return;
-#if 0
-       msg_entity = e;
-       WriteByte(MSG_ONE, 3); // svc_updatestat
-       WriteByte(MSG_ONE, 236); // STAT_TIMELIMIT
-       if(t < 0)
-               WriteCoord(MSG_ONE, autocvar_timelimit);
-       else
-               WriteCoord(MSG_ONE, (t + 1) / 60);
-#else
-       STAT(TTT_ROUNDTIMER, e) = t;
-#endif
-}
-
-void nades_Clear(entity player);
-
-void karma_Control(entity it)
-{
-       float masksize = autocvar_g_ban_default_masksize;
-       float bantime = autocvar_g_ttt_karma_bantime;
-       if(it.karmapoints >= autocvar_g_ttt_max_karma_points)
-       {
-               //Resets karmapoints to maintain the maximum
-               //PrintToChatAll("^3REWARD ^1MAXIMUM RESET");
-               GameRules_scoring_add(it, TTT_KARMA, autocvar_g_ttt_max_karma_points - it.karmapoints);
-               it.karmapoints = autocvar_g_ttt_max_karma_points;
-       }
-       else if(it.karmapoints <= autocvar_g_ttt_min_karma_points)
-       {
-               switch (autocvar_g_ttt_karma_bankick_tool)
-               {
-                       case 0:
-                       {       
-                               //force to spec
-                               PutObserverInServer(it);
-                               return;
-                       }
-                       case 1:
-                       {
-                               //kick
-                               dropclient(it);
-                               return;
-                       }
-                       case 2:
-                       {
-                               //ban and kick
-                               Ban_KickBanClient(it, bantime, masksize, "Too low karma");
-                               return;
-                       }
-                       default:
-                       {
-                               //force to spec
-                               PutObserverInServer(it);
-                               return;
-                       }
-               }
-       }
-}
-
-void karmaLoseDifference(entity attacker, entity target)
-{
-       //BASIC MATH THEORY: example: 1000 * 0.3 * (0.1 + 0.4) * 0.25 // karma points reduce when player attacked to other player
-       if (target.karmapoints < attacker.karmapoints)
-       {       
-               float decreasekarma = - ( target.karmapoints * random() * ( 0.1 + random() ) * 0.25 );
-               GameRules_scoring_add(attacker, TTT_KARMA, decreasekarma);
-               attacker.karmapoints = attacker.karmapoints + decreasekarma;
-       }
-       else if (target.karmapoints > attacker.karmapoints)
-       {
-               float decreasekarma = - ( target.karmapoints * random() * ( 0.1 + random() ) * 0.25 );
-               GameRules_scoring_add(attacker, TTT_KARMA, decreasekarma);
-               attacker.karmapoints = attacker.karmapoints + decreasekarma;
-       }
-       else
-       {
-               float decreasekarma = - ( target.karmapoints * random() * ( 0.1 + random() ) * 0.25 );
-               GameRules_scoring_add(attacker, TTT_KARMA, decreasekarma);
-               attacker.karmapoints = attacker.karmapoints + decreasekarma;
-       }
-}
-
-void karmaWinDifference(entity it)
-{
-       GameRules_scoring_add(it, SCORE, 1); // reward innocents who make it to the end of the round time limit
-       float increasekarma = ( autocvar_g_ttt_min_karma_points * random() * ( 0.1 + random() ) * 0.12 );
-       GameRules_scoring_add(it, TTT_KARMA, increasekarma);
-       it.karmapoints = it.karmapoints + increasekarma;
-}
-
-void ttt_UpdateScores(bool timed_out)
-{
-       // give players their hard-earned kills now that the round is over
-       FOREACH_CLIENT(true,
-       {
-               it.totalfrags += it.ttt_validkills;
-               if(it.ttt_validkills)
-               {
-                       GameRules_scoring_add(it, SCORE, it.ttt_validkills);
-               }
-               it.ttt_validkills = 0;
-               // player survived the round
-               if(IS_PLAYER(it) && !IS_DEAD(it)) // LegendGuard adds something for Karma 21-02-2021
-               {
-                       if((autocvar_g_ttt_reward_innocent && timed_out && it.ttt_status == TTT_STATUS_INNOCENT) 
-                       || (autocvar_g_ttt_reward_innocent && !timed_out && it.ttt_status == TTT_STATUS_INNOCENT))
-                       {
-                               karmaWinDifference(it);
-                               //PrintToChatAll(sprintf("^2REWARD ^7it.karmapoints: ^1%f", it.karmapoints));
-                               karma_Control(it);
-                       }
-
-                       //Detective reward after investigated a corpse
-                       if((autocvar_g_ttt_reward_detective && timed_out && it.ttt_status == TTT_STATUS_DETECTIVE) 
-                       || (autocvar_g_ttt_reward_detective && !timed_out && it.ttt_status == TTT_STATUS_DETECTIVE))
-                       {
-                               if (it.investigated == true)
-                               {
-                                       karmaWinDifference(it);
-                                       it.investigated = false;
-                               }
-                               karma_Control(it);
-                       }
-
-                       if(it.ttt_status == TTT_STATUS_INNOCENT)
-                       {
-                               GameRules_scoring_add(it, TTT_RESISTS, 1);
-                               karmaWinDifference(it);
-                               //PrintToChatAll(sprintf("^2INNOCENT ^7it.karmapoints: ^1%f", it.karmapoints));
-                               karma_Control(it);
-                       }
-                       else if(it.ttt_status == TTT_STATUS_TRAITOR)
-                       {
-                               karmaWinDifference(it);
-                               //PrintToChatAll(sprintf("^1TRAITOR ^7it.karmapoints: ^1%f", it.karmapoints));
-                               karma_Control(it);
-                       }
-               }
-       });
-}
-
-float ttt_CheckWinner()
-{
-       if(round_handler_GetEndTime() > 0 && round_handler_GetEndTime() - time <= 0)
-       {
-               // if the match times out, innocents win too!
-               Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_TTT_INNOCENT_WIN);
-               Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_TTT_INNOCENT_WIN);
-               FOREACH_CLIENT(true,
-               {
-                       if(IS_PLAYER(it))
-                               nades_Clear(it);
-                       ttt_FakeTimeLimit(it, -1);
-               });
-
-               ttt_UpdateScores(true);
-
-               allowed_to_spawn = false;
-               game_stopped = true;
-               round_handler_Init(5, autocvar_g_ttt_warmup, autocvar_g_ttt_round_timelimit);
-               return 1;
-       }
-
-       int innocent_count = 0, traitor_count = 0, detective_count = 0;
-       FOREACH_CLIENT(IS_PLAYER(it) && !IS_DEAD(it),
-       {
-               if(it.ttt_status == TTT_STATUS_INNOCENT)
-                       innocent_count++;
-               else if(it.ttt_status == TTT_STATUS_TRAITOR)
-                       traitor_count++;
-               else if(it.ttt_status == TTT_STATUS_DETECTIVE) //LegendGuard adds detective_count 20-02-2021 
-                       detective_count++;
-       });
-       if(innocent_count > 0 && traitor_count > 0)
-       {
-               return 0;
-       }
-
-       if(traitor_count > 0) // traitors win
-       {
-               Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_TTT_TRAITOR_WIN);
-               Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_TTT_TRAITOR_WIN);
-       }
-       else if(innocent_count > 0) // innocents win
-       {
-               Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_TTT_INNOCENT_WIN);
-               Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_TTT_INNOCENT_WIN);
-       }
-       else if (detective_count > 0 && innocent_count > 0) // detectives are same as innocents win
-       {
-               Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_TTT_INNOCENT_WIN);
-               Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_TTT_INNOCENT_WIN);
-       }
-       else
-       {
-               Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_ROUND_TIED);
-               Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_ROUND_TIED);
-       }
-
-       ttt_UpdateScores(false);
-
-       allowed_to_spawn = false;
-       game_stopped = true;
-       round_handler_Init(5, autocvar_g_ttt_warmup, autocvar_g_ttt_round_timelimit);
-
-       FOREACH_CLIENT(true,
-       {
-               if(IS_PLAYER(it))
-               {
-                       it.respawn_flags = RESPAWN_SILENT; //CSQC print output respawn lib.qh error fix
-                       nades_Clear(it);
-               }
-               ttt_FakeTimeLimit(it, -1);
-       });
-
-       return 1;
-}
-
-void ttt_RoundStart()
-{
-       allowed_to_spawn = boolean(warmup_stage);
-       int playercount = 0;
-       
-       FOREACH_CLIENT(true,
-       {
-               if(IS_PLAYER(it) && !IS_DEAD(it))
-               {
-                       ++playercount;
-                       it.ttt_status = TTT_STATUS_INNOCENT;
-               }
-               else
-                       it.ttt_status = 0; // this is mostly a safety check; if a client manages to somehow maintain a ttt status, clear it before the round starts!
-               it.ttt_validkills = 0;
-       });
-       
-       int innocent_count = bound(1, ((autocvar_g_ttt_innocent_count >= 1) ? autocvar_g_ttt_innocent_count : floor(playercount * autocvar_g_ttt_innocent_count)), playercount - 1); // 20%, but ensure at least 1 and less than total
-       int total_innocents = 0;
-       //int traitor_count = bound(1, ((autocvar_g_ttt_traitor_count >= 1) ? autocvar_g_ttt_traitor_count : floor(playercount * autocvar_g_ttt_traitor_count)), playercount - 1); // 20%, but ensure at least 1 and less than total
-       int total_traitors = 0;
-       //int detective_count = bound(1, ((autocvar_g_ttt_detective_count >= 1) ? autocvar_g_ttt_detective_count : floor(playercount * autocvar_g_ttt_detective_count)), playercount - 1); // 20%, but ensure at least 1 and less than total
-       int total_detectives = 0;
-
-       //innocents TOTAL
-       FOREACH_CLIENT_RANDOM(IS_PLAYER(it) && !IS_DEAD(it),
-       {
-               if(total_innocents >= innocent_count)
-                       break;
-               //LegendGuard fixes the round start again 22-03-2021
-               total_innocents++;
-               if (total_innocents <= 1)
-               {
-                       if (total_traitors <= 1)
-                       {
-                               total_traitors++;
-                               it.ttt_status = TTT_STATUS_TRAITOR;
-                       }
-               }
-               else if (total_innocents == 2)
-               {
-                       if (total_detectives >= 1)
-                               break;
-                       else
-                       {
-                               total_detectives++;
-                               it.ttt_status = TTT_STATUS_DETECTIVE;
-                       }
-               }
-               else if (total_innocents == 5)
-               {
-                       if (total_detectives >= 2)
-                               break;
-                       else
-                       {
-                               total_detectives++;
-                               it.ttt_status = TTT_STATUS_DETECTIVE;
-                       }
-               }
-               else if (total_innocents >= 7)
-               {
-                       if (total_detectives >= 3)
-                               break;
-                       else if (total_traitors == 3)
-                       {
-                               total_traitors++;
-                               it.ttt_status = TTT_STATUS_TRAITOR;
-                       }
-                       else
-                       {
-                               total_detectives++;
-                               it.ttt_status = TTT_STATUS_DETECTIVE;
-                       }
-               }
-               else
-                       it.ttt_status = TTT_STATUS_TRAITOR;
-       });
-
-       FOREACH_CLIENT(IS_PLAYER(it) && !IS_DEAD(it),
-       {
-               float totalmeankarma = ((autocvar_g_ttt_max_karma_points + autocvar_g_ttt_min_karma_points + it.karmapoints) / 3);
-               karma_Control(it);
-
-               if(it.ttt_status == TTT_STATUS_INNOCENT)
-               {
-                       SetResource(it, RES_SHELLS, 50);
-                       SetResource(it, RES_BULLETS, 70);
-                       SetResource(it, RES_ROCKETS, 30);
-                       SetResource(it, RES_CELLS, 60);
-                       if (it.karmapoints <= totalmeankarma)
-                       {
-                               centerprint(it, strcat(BOLD_OPERATOR, "^1KARMA WARNING!\n^3Here, have the Rifle!"));
-                               GiveWeapon(it, WEP_RIFLE.m_id, OP_PLUS, 1);
-                       }
-                       //Gives Mine Layer weapon to the player
-                       GiveWeapon(it, WEP_MINE_LAYER.m_id, OP_PLUS, 1);
-                       Send_Notification(NOTIF_ONE_ONLY, it, MSG_CENTER, CENTER_TTT_INNOCENT);
-                       Send_Notification(NOTIF_ONE_ONLY, it, MSG_INFO, INFO_TTT_INNOCENT);
-                       //PrintToChatAll(sprintf("^1DEBUG^7: %s is ^2Innocent^7!", it.netname));
-               }
-               else if(it.ttt_status == TTT_STATUS_TRAITOR)
-               {
-                       SetResource(it, RES_SHELLS, 20);
-                       SetResource(it, RES_BULLETS, 60);
-                       SetResource(it, RES_ROCKETS, 20);
-                       SetResource(it, RES_CELLS, 40);
-                       if (it.karmapoints <= totalmeankarma)
-                       {
-                               centerprint(it, strcat(BOLD_OPERATOR, "^1KARMA WARNING!\n^3Here, have the Rifle!"));
-                               GiveWeapon(it, WEP_RIFLE.m_id, OP_PLUS, 1);
-                       }
-                       //Gives Mine Layer weapon to the player
-                       GiveWeapon(it, WEP_MINE_LAYER.m_id, OP_PLUS, 1);
-                       Send_Notification(NOTIF_ONE_ONLY, it, MSG_CENTER, CENTER_TTT_TRAITOR);
-                       Send_Notification(NOTIF_ONE_ONLY, it, MSG_INFO, INFO_TTT_TRAITOR);
-                       //PrintToChatAll(sprintf("^1DEBUG^7: %s is ^1Traitor^7!", it.netname));
-               }
-               else if(it.ttt_status == TTT_STATUS_DETECTIVE)
-               {
-                       SetResource(it, RES_ROCKETS, 20);
-                       if (it.karmapoints <= totalmeankarma)
-                       {
-                               centerprint(it, strcat(BOLD_OPERATOR, "^1KARMA WARNING!\n^3Here, have the Rifle!"));
-                               GiveWeapon(it, WEP_RIFLE.m_id, OP_PLUS, 1);
-                       }
-                       //Gives Shockwave and Mine Layer weapon to the player
-                       GiveWeapon(it, WEP_SHOCKWAVE.m_id, OP_PLUS, 1);
-                       GiveWeapon(it, WEP_MINE_LAYER.m_id, OP_PLUS, 1);
-                       Send_Notification(NOTIF_ONE_ONLY, it, MSG_CENTER, CENTER_TTT_DETECTIVE);
-                       Send_Notification(NOTIF_ONE_ONLY, it, MSG_INFO, INFO_TTT_DETECTIVE);
-                       PrintToChatAll(sprintf("%s is ^4Detective^7!", it.netname));
-               }
-               ttt_FakeTimeLimit(it, round_handler_GetEndTime());
-       });
-}
-
-bool ttt_CheckPlayers()
-{
-       static int prev_missing_players;
-       allowed_to_spawn = true;
-       int playercount = 0;
-
-       FOREACH_CLIENT(IS_PLAYER(it) && !IS_DEAD(it),
-       {       
-               //PrintToChatAll(sprintf("it.karmapoints ^5begin: ^3%f",it.karmapoints));
-               //Karma points start
-               if (it.karmastarted != true)
-               {
-                       GameRules_scoring_add(it, TTT_KARMA, autocvar_g_ttt_max_karma_points - it.karmapoints);
-                       it.karmapoints = autocvar_g_ttt_max_karma_points;
-                       it.karmastarted = true;
-               }
-               karma_Control(it);
-               ++playercount;
-               //PrintToChatAll(sprintf("it.karmapoints ^6end: ^3%f",it.karmapoints));
-       });
-
-       if (playercount >= 2)
-       {
-               if(prev_missing_players > 0)
-                       Kill_Notification(NOTIF_ALL, NULL, MSG_CENTER, CPID_MISSING_PLAYERS);
-               prev_missing_players = -1;
-               return true;
-       }
-
-       if(playercount == 0)
-       {
-               if(prev_missing_players > 0)
-                       Kill_Notification(NOTIF_ALL, NULL, MSG_CENTER, CPID_MISSING_PLAYERS);
-               prev_missing_players = -1;
-               return false;
-       }
-
-       // if we get here, only 1 player is missing
-       if(prev_missing_players != 1)
-       {
-               Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_MISSING_PLAYERS, 1);
-               prev_missing_players = 1;
-       }
-       return false;
-}
-
-bool ttt_isEliminated(entity e)
-{
-       if(e.caplayer == 1 && (IS_DEAD(e) || e.frags == FRAGS_PLAYER_OUT_OF_GAME))
-               return true;
-       if(e.caplayer == 0.5)
-               return true;
-       return false;
-}
-
-void ttt_Initialize() // run at the start of a match, initiates game mode
-{
-       GameRules_scoring(0, SFL_SORT_PRIO_PRIMARY, 0, {
-               field(SP_TTT_RESISTS, "resists", 0);
-               field(SP_TTT_KARMA, "karma", SFL_SORT_PRIO_SECONDARY); //LegendGuard adds Karma points in the scoreboard 22-02-2021
-       });
-
-       allowed_to_spawn = true;
-       round_handler_Spawn(ttt_CheckPlayers, ttt_CheckWinner, ttt_RoundStart);
-       round_handler_Init(5, autocvar_g_ttt_warmup, autocvar_g_ttt_round_timelimit);
-       EliminatedPlayers_Init(ttt_isEliminated);
-}
-
-void checkWeaponDeathtype(entity target, float deathtype)
-{
-       switch (deathtype)
-       {
-               case WEP_ARC.m_id: case 276: case 788: target.killedwithweapon = "Impacted by the Arc's electric shock"; return;
-               case WEP_BLASTER.m_id: case 513: target.killedwithweapon = "Blasted by the Blaster"; return;
-               case WEP_CRYLINK.m_id: case 263: case 519: target.killedwithweapon = "Shot by the Crylink"; return;
-               case WEP_DEVASTATOR.m_id: case 522: target.killedwithweapon = "Bombarded by the Devastator"; return;
-               case WEP_ELECTRO.m_id: case 262: case 518: case 1542: target.killedwithweapon = "Electrocuted by the Electro"; return;
-               case WEP_FIREBALL.m_id: case 273: case 529: case 1297: target.killedwithweapon = "Burned by the Fireball"; return;
-               case WEP_HAGAR.m_id: target.killedwithweapon = "Gunned by the Hagar"; return;
-               case WEP_HOOK.m_id: case 1805: target.killedwithweapon = "Caught in Hook gravity bomb"; return;
-               case WEP_MACHINEGUN.m_id: target.activekillerrole = true; target.killedwithweapon = "Riddled full of holes by the Machine Gun"; return;
-               case WEP_MINE_LAYER.m_id: target.killedwithweapon = "Exploited by the Mine Layer"; return;
-               case WEP_MORTAR.m_id: case 516: case 1284: target.killedwithweapon = "Blew up with the Mortar"; return;
-               case WEP_RIFLE.m_id: target.activekillerrole = true; target.killedwithweapon = "Sniped by the Rifle"; return;
-               case WEP_SEEKER.m_id: target.killedwithweapon = "Blasted by the Seeker"; return;
-               case WEP_SHOCKWAVE.m_id: target.killedwithweapon = "Gunned down by the Shockwave"; return;
-               case 275: target.killedwithweapon = "Knocked by the Shockwave"; return;
-               case WEP_SHOTGUN.m_id: target.activekillerrole = true; target.killedwithweapon = "Shot by Shotgun"; return;
-               case 258: target.killedwithweapon = "Knocked by the Shotgun"; return;
-               case WEP_TUBA.m_id: target.killedwithweapon = "Ear pain by the @!#%'n Tuba"; return;
-               case WEP_VAPORIZER.m_id: case 257: case 769: target.killedwithweapon = "Sniped by the Vaporizer"; return;
-               case WEP_VORTEX.m_id: target.killedwithweapon = "Sniped by the Vortex"; return;
-               case DEATH_FALL.m_id: target.killedwithweapon = "Fall"; return;
-               case DEATH_FIRE.m_id: target.killedwithweapon = "Burned with the fire"; return;
-               case DEATH_LAVA.m_id: target.killedwithweapon = "Burned in lava"; return;
-               case DEATH_MIRRORDAMAGE.m_id: target.killedwithweapon = "Suicide"; return;
-               case DEATH_SLIME.m_id: target.killedwithweapon = "Melted in slime"; return;
-               case DEATH_TELEFRAG.m_id: target.killedwithweapon = "Telefragged"; return;
-               default: target.killedwithweapon = "Unknown"; return;
-       }
-}
-
-void ReduceKarmaPointsandFrags(entity frag_attacker, entity frag_target, float frag_deathtype, entity wep_ent)
-{
-       karmaLoseDifference(frag_attacker, frag_target);
-       GiveFrags(frag_attacker, frag_target, ((autocvar_g_ttt_punish_teamkill) ? -1 : -2), frag_deathtype, wep_ent.weaponentity_fld);
-       karma_Control(frag_attacker);
-       frag_target.whokilled = frag_attacker.netname;
-}
-
-// ==============
-// Hook Functions
-// ==============
-
-MUTATOR_HOOKFUNCTION(ttt, ClientObituary)
-{
-       // LegendGuard's IDEA: To adjust the grade of severity of karma, 
-       // we could add if sentence per weapons and adjust each weapon attack
-       // its own grade. Instead doing random decrease grade 22-02-2021
-       
-       // in ttt, announcing a frag would tell everyone who the traitor is
-       entity frag_attacker = M_ARGV(1, entity);
-       entity frag_target = M_ARGV(2, entity);
-       
-       if(IS_PLAYER(frag_attacker) && frag_attacker != frag_target)
-       {
-               float frag_deathtype = M_ARGV(3, float);
-               entity wep_ent = M_ARGV(4, entity);
-               
-               //PrintToChatAll(strcat("deathtype var: ", ftos(frag_deathtype)));
-               checkWeaponDeathtype(frag_target, frag_deathtype);
-               // "team" kill, a point is awarded to the player by default so we must take it away plus an extra one
-               // unless the player is going to be punished for suicide, in which case just remove one
-               if(frag_attacker.ttt_status == frag_target.ttt_status)
-               {
-                       //PrintToChatAll("^1DEBUG^7: A ^2PLAYER^7 has fragged a ^2PLAYER OF HIS OWN TEAM^7, TOO BAD!");
-                       ReduceKarmaPointsandFrags(frag_attacker, frag_target, frag_deathtype, wep_ent);
-                       switch (frag_attacker.ttt_status)
-                       {
-                               case TTT_STATUS_INNOCENT: frag_target.killerrole = "\n^3Killer role: ^2Innocent"; return;
-                               case TTT_STATUS_TRAITOR: frag_target.killerrole = "\n^3Killer role: ^1Traitor"; return;
-                               case TTT_STATUS_DETECTIVE: frag_target.killerrole = "\n^3Killer role: ^4Detective"; return;
-                               default: return;
-                       }
-                       //PrintToChatAll(sprintf("frag_attacker.karmapoints: ^1%f", frag_attacker.karmapoints));
-               }
-
-               if(frag_attacker.ttt_status == TTT_STATUS_DETECTIVE)
-               {
-                       if (frag_target.ttt_status == TTT_STATUS_INNOCENT || frag_target.ttt_status == TTT_STATUS_DETECTIVE)
-                       {       
-                               //PrintToChatAll("^1DEBUG^7: A ^4Detective^7 fragged an ^2Innocent^7/^4Detective^7, TOO BAD!");
-                               ReduceKarmaPointsandFrags(frag_attacker, frag_target, frag_deathtype, wep_ent);
-                               frag_target.killerrole = "\n^3Killer role: ^4Detective";
-                               //PrintToChatAll(sprintf("frag_attacker.karmapoints: ^1%f", frag_attacker.karmapoints));
-                       }
-                       else
-                       {
-                               frag_target.whokilled = frag_attacker.netname;
-                               frag_target.killerrole = "\n^3Killer role: ^4Detective";
-                       }
-               }
-
-               if (frag_attacker.ttt_status == TTT_STATUS_INNOCENT)
-               {
-                       if (frag_target.ttt_status == TTT_STATUS_DETECTIVE)
-                       {
-                               //PrintToChatAll("^1DEBUG^7: An ^2Innocent^7 fragged a ^4Detective^7, TOO BAD!");
-                               ReduceKarmaPointsandFrags(frag_attacker, frag_target, frag_deathtype, wep_ent);
-                               frag_target.killerrole = "\n^3Killer role: ^2Innocent";
-                       }
-                       else
-                       {
-                               frag_target.whokilled = frag_attacker.netname;
-                               frag_target.killerrole = "\n^3Killer role: ^2Innocent";
-                       }
-               }
-               
-               if (frag_attacker.ttt_status == TTT_STATUS_TRAITOR)
-               {
-                       if (frag_target.ttt_status == TTT_STATUS_INNOCENT)
-                       {
-                               frag_target.whokilled = frag_attacker.netname;
-                               frag_target.killerrole = "\n^3Killer role: ^1Traitor";
-                       }
-                       else
-                       {
-                               frag_target.whokilled = frag_attacker.netname;
-                               frag_target.killerrole = "\n^3Killer role: ^1Traitor";
-                       }
-               }
-               //if ttt_status is 1, means innocent, 2 means traitor, 3 means detective, TODO: the bots: frag_attacker(1) shouldn't attack to frag_target(3)
-               //PrintToChatAll(sprintf("^1DEBUG^7: frag_attacker.ttt_status is ^3%s^7",ftos(frag_attacker.ttt_status)));
-               //PrintToChatAll(sprintf("^1DEBUG^7: frag_target.ttt_status is ^3%s^7",ftos(frag_target.ttt_status)));
-       }
-
-       //TODO: try to do a "find out" if a detective can see who fragged to who if possible 21-02-2021
-       M_ARGV(5, bool) = true; // anonymous attacker
-}
-
-//karma weapon damage, halve the damage attack when player has low karma 20-03-2021
-MUTATOR_HOOKFUNCTION(ttt, Damage_Calculate)
-{
-       entity attacker = M_ARGV(1, entity);
-       entity target = M_ARGV(2, entity);
-       float deathtype = M_ARGV(3, float);
-       float damage = M_ARGV(4, float);
-       vector force = M_ARGV(6, vector);
-       string corpsemessagestrcat = "";
-
-       if (autocvar_g_ttt_karma_damageactive != false)
-       {
-               if (IS_PLAYER(attacker))
-               {
-                       if(target == attacker) // damage done to yourself
-                       {
-                               damage /= autocvar_g_weapondamagefactor / (attacker.karmapoints / autocvar_g_ttt_max_karma_points);
-                               force /= autocvar_g_weaponforcefactor / (attacker.karmapoints / autocvar_g_ttt_max_karma_points);
-                       }
-                       else if (target != attacker)
-                       {
-                               damage /= autocvar_g_weapondamagefactor / (attacker.karmapoints / autocvar_g_ttt_max_karma_points);
-                               force /= autocvar_g_weaponforcefactor / (attacker.karmapoints / autocvar_g_ttt_max_karma_points);
-                       }
-                       else
-                       {
-                               damage *= autocvar_g_weapondamagefactor;
-                               force *= autocvar_g_weaponforcefactor;
-                       }
-               }
-       }
-
-       //DETECTIVE CORPSE DETECTION SKILL 21-03-2021
-       if (attacker.ttt_status == TTT_STATUS_DETECTIVE)
-       {
-               if(IS_DEAD(target))
-               {
-                       //Shockwave weapon as radar gun to check the corpses 22-03-2021
-                       if(DEATH_ISWEAPON(deathtype, WEP_SHOCKWAVE))
-                       {
-                               if (target.killedwithweapon == "")
-                                       target.killedwithweapon = "UNKNOWN CAUSE";
-                               
-                               if (target.activekillerrole != true)
-                                       target.killerrole = "";
-
-                               string killedbyphrase = strcat("\n^3Killed by:^7 ", target.whokilled, target.killerrole); 
-                               string wepkilledphrase = strcat("\n^3Cause:^7 ", target.killedwithweapon);
-                               if (target.whokilled == "")
-                               {
-                                       killedbyphrase = "";
-                                       if (target.killedwithweapon == "")
-                                               wepkilledphrase = "\n^3Cause:^7 UNCLEAR";
-                               }
-
-                               damage = 0;
-                               force = '0 0 0';
-                               if (target.ttt_status == TTT_STATUS_INNOCENT)
-                               {
-                                       //try to add centerprint message for chat privately if possible
-                                       corpsemessagestrcat = strcat("\n^3Name:^7 ", target.netname, "\n^3Role: ^2Innocent", killedbyphrase, wepkilledphrase);
-                                       centerprint(attacker, strcat(BOLD_OPERATOR, corpsemessagestrcat));//("\n^6Name^3:^7 ", target.netname, "\n^5Role^3: ^2Innocent\n", "^1Killed by^3:^7 ", target.whokilled)));
-                               }
-                               else if (target.ttt_status == TTT_STATUS_TRAITOR)
-                               {
-                                       corpsemessagestrcat = strcat("\n^3Name:^7 ", target.netname, "\n^3Role: ^1Traitor", killedbyphrase, wepkilledphrase);
-                                       centerprint(attacker, strcat(BOLD_OPERATOR, corpsemessagestrcat));//("\n^6Name^3:^7 ", target.netname, "\n^5Role^3: ^1Traitor\n", "^1Killed by^3:^7 ", target.whokilled)));
-                               }
-                               else if (target.ttt_status == TTT_STATUS_DETECTIVE)
-                               {
-                                       corpsemessagestrcat = strcat("\n^3Name:^7 ", target.netname, "\n^3Role: ^4Detective", killedbyphrase, wepkilledphrase);
-                                       centerprint(attacker, strcat(BOLD_OPERATOR, corpsemessagestrcat));//("\n^6Name^3:^7 ", target.netname, "\n^5Role^3: ^4Detective\n", "^1Killed by^3:^7 ", target.whokilled)));
-                               }
-                               attacker.investigated = true;
-                       }
-               }
-       }
-
-       M_ARGV(4, float) = damage;
-       M_ARGV(6, vector) = force;
-}
-
-MUTATOR_HOOKFUNCTION(ttt, PlayerPreThink)
-{
-       entity player = M_ARGV(0, entity);
-       
-       if(IS_PLAYER(player) || player.caplayer)
-       {
-               // update the scoreboard colour display to out the real killer at the end of the round
-               // running this every frame to avoid cheats
-               int plcolor = TTT_COLOR_INNOCENT;
-               if(player.ttt_status == TTT_STATUS_INNOCENT && game_stopped) //Innocent status by default
-                       plcolor = TTT_COLOR_INNOCENT;
-               if(player.ttt_status == TTT_STATUS_TRAITOR && game_stopped)
-                       plcolor = TTT_COLOR_TRAITOR;
-               //LegendGuard adds for Detective 21-02-2021
-               if(player.ttt_status == TTT_STATUS_DETECTIVE)// && game_stopped)
-                       plcolor = TTT_COLOR_DETECTIVE;
-               setcolor(player, plcolor);
-       }
-
-       //CORPSE FEATURE 10-03-2021
-       if (IS_DEAD(player))
-       {
-               player.event_damage = func_null;
-               //player.health = 0;
-               player.solid = SOLID_CORPSE;
-               set_movetype(player, MOVETYPE_STEP); //test with MOVETYPE_TOSS or MOVETYPE_WALK (it's like sliding object) or MOVETYPE_BOUNCE (maybe not good)
-       }
-}
-
-MUTATOR_HOOKFUNCTION(ttt, PlayerSpawn)
-{
-       entity player = M_ARGV(0, entity);
-
-       player.ttt_status = 0;
-       player.ttt_validkills = 0;
-       player.caplayer = 1;
-       if (!warmup_stage)
-               eliminatedPlayers.SendFlags |= 1;
-}
-
-MUTATOR_HOOKFUNCTION(ttt, ForbidSpawn)
-{
-       entity player = M_ARGV(0, entity);
-
-       // spectators / observers that weren't playing can join; they are
-       // immediately forced to observe in the PutClientInServer hook
-       // this way they are put in a team and can play in the next round
-       if (!allowed_to_spawn && player.caplayer)
-               return true;
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(ttt, PutClientInServer)
-{
-       entity player = M_ARGV(0, entity);
-
-       if (!allowed_to_spawn && IS_PLAYER(player)) // this is true even when player is trying to join
-       {
-               TRANSMUTE(Observer, player);
-               if (CS(player).jointime != time && !player.caplayer) // not when connecting
-               {
-                       player.caplayer = 0.5;
-                       Send_Notification(NOTIF_ONE_ONLY, player, MSG_INFO, INFO_CA_JOIN_LATE);
-               }
-       }
-}
-
-MUTATOR_HOOKFUNCTION(ttt, reset_map_players)
-{
-       FOREACH_CLIENT(true, {
-               CS(it).killcount = 0;
-               it.ttt_status = 0;
-               ttt_FakeTimeLimit(it, -1); // restore original timelimit
-               if (!it.caplayer && IS_BOT_CLIENT(it))
-                       it.caplayer = 1;
-               if (it.caplayer)
-               {
-                       TRANSMUTE(Player, it);
-                       it.caplayer = 1;
-                       it.respawn_flags = RESPAWN_SILENT; //CSQC print output respawn lib.qh error fix
-                       PutClientInServer(it);
-               }
-       });
-       bot_relinkplayerlist();
-       return true;
-}
-
-MUTATOR_HOOKFUNCTION(ttt, reset_map_global)
-{
-       allowed_to_spawn = true;
-       return true;
-}
-
-entity ttt_LastPlayerForTeam(entity this)
-{
-       entity last_pl = NULL;
-       FOREACH_CLIENT(IS_PLAYER(it) && it != this, {
-               if (!IS_DEAD(it) && this.ttt_status == it.ttt_status)
-               {
-                       if (!last_pl)
-                       {
-                               last_pl = it;
-                       }
-                       else
-                               return NULL;
-               }
-       });
-       return last_pl;
-}
-
-void ttt_LastPlayerForTeam_Notify(entity this)
-{
-       if (!warmup_stage && round_handler_IsActive() && round_handler_IsRoundStarted())
-       {
-               entity pl = ttt_LastPlayerForTeam(this);
-               if (pl)
-                       Send_Notification(NOTIF_ONE_ONLY, pl, MSG_CENTER, CENTER_ALONE);
-       }
-}
-
-MUTATOR_HOOKFUNCTION(ttt, PlayerDies)
-{
-       entity frag_attacker = M_ARGV(1, entity);
-       entity frag_target = M_ARGV(2, entity);
-       //float frag_deathtype = M_ARGV(3, float);
-
-       ttt_LastPlayerForTeam_Notify(frag_target);
-       if (!allowed_to_spawn)
-       {
-               frag_target.respawn_flags = RESPAWN_DENY;
-               // prevent unwanted sudden rejoin as spectator and movement of spectator camera
-               frag_target.respawn_time = time + 2;
-       }
-       frag_target.respawn_flags |= RESPAWN_DENY;
-       frag_target.event_damage = func_null;
-       frag_target.health = 0;
-       
-       if (!warmup_stage)
-       {
-               eliminatedPlayers.SendFlags |= 1;
-               if (IS_BOT_CLIENT(frag_target))
-                       bot_clear(frag_target);
-       }
-       
-       //if(frag_attacker.ttt_status == frag_target.ttt_status)
-       // killed an ally! punishment is sentenced
-       if(frag_attacker.ttt_status == TTT_STATUS_DETECTIVE)
-       {
-               if (frag_target.ttt_status == TTT_STATUS_INNOCENT)
-               {
-                       //PrintToChatAll("^1DEBUG^7: ^4DETECTIVE ^1DAMAGE/DEAD^7 HAS TAKEN!");
-                       //30 damage points deal
-                       Damage(frag_attacker, frag_attacker, frag_attacker, 30, DEATH_MIRRORDAMAGE.m_id, DMG_NOWEP, frag_attacker.origin, '0 0 0');
-               }
-       }
-       if (frag_attacker.ttt_status == TTT_STATUS_INNOCENT)
-       {
-               if (frag_target.ttt_status == TTT_STATUS_DETECTIVE)
-               {
-                       //PrintToChatAll("^1DEBUG^7: ^2INNOCENT ^1DAMAGE/DEAD^7 HAS TAKEN!");
-                       //30 damage points deal
-                       Damage(frag_attacker, frag_attacker, frag_attacker, 30, DEATH_MIRRORDAMAGE.m_id, DMG_NOWEP, frag_attacker.origin, '0 0 0');
-               }
-       }
-       return true;
-}
-
-MUTATOR_HOOKFUNCTION(ttt, ClientDisconnect)
-{
-       entity player = M_ARGV(0, entity);
-
-       if (IS_PLAYER(player) && !IS_DEAD(player))
-               ttt_LastPlayerForTeam_Notify(player);
-       return true;
-}
-
-MUTATOR_HOOKFUNCTION(ttt, MakePlayerObserver)
-{
-       // LegendGuard, here is where spectators shouldn't talk to any players to say the hints or who is who 21-10-2021
-       entity player = M_ARGV(0, entity);
-
-       if (IS_PLAYER(player) && !IS_DEAD(player))
-               ttt_LastPlayerForTeam_Notify(player);
-       if (player.killindicator_teamchange == -2) // player wants to spectate
-               player.caplayer = 0;
-       if (player.caplayer)
-               player.frags = FRAGS_PLAYER_OUT_OF_GAME;
-       if (!warmup_stage)
-               eliminatedPlayers.SendFlags |= 1;
-       if (!player.caplayer)
-       {
-               player.ttt_validkills = 0;
-               player.ttt_status = 0;
-               ttt_FakeTimeLimit(player, -1); // restore original timelimit
-               return false;  // allow team reset
-       }
-       return true;  // prevent team reset
-}
-
-MUTATOR_HOOKFUNCTION(ttt, Scores_CountFragsRemaining)
-{
-       // announce remaining frags?
-       return true;
-}
-
-MUTATOR_HOOKFUNCTION(ttt, GiveFragsForKill, CBC_ORDER_FIRST)
-{
-       entity frag_attacker = M_ARGV(0, entity);
-       if(!warmup_stage && round_handler_IsActive() && round_handler_IsRoundStarted())
-               frag_attacker.ttt_validkills += M_ARGV(2, float);
-       M_ARGV(2, float) = 0; // score will be given to the winner when the round ends
-       return true;
-}
-
-MUTATOR_HOOKFUNCTION(ttt, AddPlayerScore)
-{
-       // add scorefield for scoreboard here
-       entity scorefield = M_ARGV(0, entity);
-       if(scorefield == SP_KILLS || scorefield == SP_DEATHS || scorefield == SP_SUICIDES || scorefield == SP_DMG || scorefield == SP_DMGTAKEN)
-               M_ARGV(1, float) = 0; // don't report that the player has killed or been killed, that would out them as a traitor!
-}
-
-MUTATOR_HOOKFUNCTION(ttt, CalculateRespawnTime)
-{
-       // no respawn calculations needed, player is forced to spectate anyway
-       return true;
-}
-
-MUTATOR_HOOKFUNCTION(ttt, Bot_FixCount, CBC_ORDER_EXCLUSIVE)
-{
-       FOREACH_CLIENT(IS_REAL_CLIENT(it), {
-               if (IS_PLAYER(it) || it.caplayer == 1)
-                       ++M_ARGV(0, int);
-               ++M_ARGV(1, int);
-       });
-       return true;
-}
-
-MUTATOR_HOOKFUNCTION(ttt, ClientCommand_Spectate)
-{
-       entity player = M_ARGV(0, entity);
-
-       if (player.caplayer)
-       {
-               // they're going to spec, we can do other checks
-               if (autocvar_sv_spectate && (IS_SPEC(player) || IS_OBSERVER(player)))
-                       Send_Notification(NOTIF_ONE_ONLY, player, MSG_INFO, INFO_CA_LEAVE);
-               return MUT_SPECCMD_FORCE;
-       }
-
-       return MUT_SPECCMD_CONTINUE;
-}
-
-MUTATOR_HOOKFUNCTION(ttt, GetPlayerStatus)
-{
-       entity player = M_ARGV(0, entity);
-
-       return player.caplayer == 1;
-}
-
-MUTATOR_HOOKFUNCTION(ttt, BotShouldAttack)
-{
-       //TODO: LegendGuard, try bots attack to innocents vs traitors, detectives must be on innocents team 21-02-2021
-       entity bot = M_ARGV(0, entity);
-       entity targ = M_ARGV(1, entity);
-
-       if(targ.ttt_status == bot.ttt_status)
-       {
-               return true;
-       }
-       
-       if(targ.ttt_status == TTT_STATUS_DETECTIVE)
-       {
-               if(bot.ttt_status == TTT_STATUS_INNOCENT)
-                       return false;
-       }
-}
diff --git a/qcsrc/common/gamemodes/gamemode/ttt/sv_ttt.qh b/qcsrc/common/gamemodes/gamemode/ttt/sv_ttt.qh
deleted file mode 100644 (file)
index 5046924..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-#pragma once
-
-#include <common/mutators/base.qh>
-#include <common/scores.qh>
-void ttt_Initialize();
-
-REGISTER_MUTATOR(ttt, false)
-{
-    MUTATOR_STATIC();
-       MUTATOR_ONADD
-       {
-               ttt_Initialize();
-       }
-       return false;
-}
-
-.int ttt_validkills; // store the player's valid kills to be given at the end of the match (avoid exposing their score until then)
-.float karmapoints; //LegendGuard adds karma points to store player status 22-02-2021
-.string whokilled; //LegendGuard sets a variable to know who killed who 22-03-2021
-.string killerrole; //LegendGuard sets a variable to identify killer role 25-03-2021
-.string killedwithweapon; //LegendGuard sets a variable to know what cause provoked to the victim 23-03-2021
-.bool investigated; //LegendGuard sets a bool to make sure if detective investigated already a corpse once 24-03-2021
-.bool karmastarted; //LegendGuard fixes with a bool when round start for karma points
-.bool activekillerrole; //LegendGuard sets a variable to active killer role 25-03-2021
\ No newline at end of file
diff --git a/qcsrc/common/gamemodes/gamemode/ttt/ttt.qc b/qcsrc/common/gamemodes/gamemode/ttt/ttt.qc
deleted file mode 100644 (file)
index 0e43e09..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include "ttt.qh"
diff --git a/qcsrc/common/gamemodes/gamemode/ttt/ttt.qh b/qcsrc/common/gamemodes/gamemode/ttt/ttt.qh
deleted file mode 100644 (file)
index 08c4831..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-#pragma once
-
-#include <common/gamemodes/gamemode/lms/lms.qh>
-#include <common/mapinfo.qh>
-
-#ifdef CSQC
-void HUD_Mod_TTT(vector pos, vector mySize);
-#endif
-CLASS(TroubleinTerroristTown, Gametype)
-    INIT(TroubleinTerroristTown)
-    {
-        this.gametype_init(this, _("Trouble in Terrorist Town"),"ttt","g_ttt",GAMETYPE_FLAG_USEPOINTS,"","timelimit=30 pointlimit=20",_("A group of space terrorists have traitors among them. Traitors must kill terrorists, while the terrorists have to try to find and kill the traitors"));
-    }
-    METHOD(TroubleinTerroristTown, m_isAlwaysSupported, bool(Gametype this, int spawnpoints, float diameter))
-    {
-        return true;
-    }
-    METHOD(TroubleinTerroristTown, m_isForcedSupported, bool(Gametype this))
-    {
-        if(!cvar("g_ttt_not_lms_maps"))
-        {
-            // if this is unset, all LMS maps support TroubleinTerroristTown too
-            if(!(MapInfo_Map_supportedGametypes & this.m_flags) && (MapInfo_Map_supportedGametypes & MAPINFO_TYPE_LMS.m_flags))
-                return true; // TODO: references another gametype (alternatively, we could check which gamemodes are always enabled and append this if any are supported)
-        }
-        return false;
-    }
-#ifdef CSQC
-    ATTRIB(TroubleinTerroristTown, m_modicons, void(vector pos, vector mySize), HUD_Mod_TTT);
-#endif
-ENDCLASS(TroubleinTerroristTown)
-REGISTER_GAMETYPE(TTT, NEW(TroubleinTerroristTown));
-
-#ifdef GAMEQC
-// shared state signalling the player's ttt status
-//TODO: add Detective STATUS and COLOR 20-02-2021
-.int ttt_status;
-const int TTT_STATUS_INNOCENT = 1;
-const int TTT_STATUS_TRAITOR = 2;
-const int TTT_STATUS_DETECTIVE = 3;
-
-// hardcoded player colors for ttt
-const int TTT_COLOR_DETECTIVE = 221; // blue
-const int TTT_COLOR_INNOCENT = 51; // green
-const int TTT_COLOR_TRAITOR = 68; // red
-#endif
index 7a43de5a9d4ed675cdb165829a04358a5da1e3c2..f192e5f113527da349752577b6428f963788329a 100644 (file)
@@ -439,17 +439,17 @@ string multiteam_info_sprintf(string input, string teamname) { return ((input !=
 
     MSG_INFO_NOTIF(TEAMCHANGE_LARGERTEAM,                   N_CONSOLE,  0, 0, "", "",           "",                     _("^BGYou cannot change to a larger team"), "")
     MSG_INFO_NOTIF(TEAMCHANGE_NOTALLOWED,                   N_CONSOLE,  0, 0, "", "",           "",                     _("^BGYou are not allowed to change teams"), "")
-    //LegendGuard adds MSG_INFO_NOTIF for TTT 20-02-2021
+    //LegendGuard adds MSG_INFO_NOTIF for MMM 20-02-2021
     //LegendGuard adds N_CHATCON option 20-03-2021
-    MSG_INFO_NOTIF(TTT_TRAITOR,                             N_CHATCON,  0, 0, "", "",           "",                     _("^BGYou are ^K1Traitor^BG!"), "")
-    MSG_INFO_NOTIF(TTT_TRAITOR_WIN,                         N_CONSOLE,  0, 0, "", "",           "",                     _("^K1Traitors^BG win the round"), "")
+    MSG_INFO_NOTIF(MMM_MURDERER,                            N_CHATCON,  0, 0, "", "",           "",                     _("^BGYou are ^K1Murderer^BG!"), "")
+    MSG_INFO_NOTIF(MMM_MURDERER_WIN,                        N_CONSOLE,  0, 0, "", "",           "",                     _("^K1Murderers^BG win the round"), "")
     
     //LegendGuard adds N_CHATCON option 20-03-2021
-    MSG_INFO_NOTIF(TTT_INNOCENT,                            N_CHATCON,  0, 0, "", "",           "",                     _("^BGYou are ^F1Innocent^BG!"), "")
-    MSG_INFO_NOTIF(TTT_INNOCENT_WIN,                        N_CONSOLE,  0, 0, "", "",           "",                     _("^F1Innocents^BG win the round"), "")
+    MSG_INFO_NOTIF(MMM_CIVILIAN,                            N_CHATCON,  0, 0, "", "",           "",                     _("^BGYou are ^F1Civilian^BG!"), "")
+    MSG_INFO_NOTIF(MMM_CIVILIAN_WIN,                        N_CONSOLE,  0, 0, "", "",           "",                     _("^F1Civilians^BG win the round"), "")
     
     //LegendGuard adds N_CHATCON option 20-03-2021
-    MSG_INFO_NOTIF(TTT_DETECTIVE,                           N_CHATCON,  0, 0, "", "",           "",                     _("^BGYou are ^4Detective^BG!"), "")
+    MSG_INFO_NOTIF(MMM_SLEUTH,                              N_CHATCON,  0, 0, "", "",           "",                     _("^BGYou are ^4Sleuth^BG!"), "")
 
     MSG_INFO_NOTIF(VERSION_BETA,                            N_CONSOLE,  2, 0, "s1 s2", "",      "",                     _("^F4NOTE: ^BGThe server is running ^F1Xonotic %s (beta)^BG, you have ^F2Xonotic %s"), "")
     MSG_INFO_NOTIF(VERSION_OLD,                             N_CHATCON,  2, 0, "s1 s2", "",      "",                     _("^F4NOTE: ^BGThe server is running ^F1Xonotic %s^BG, you have ^F2Xonotic %s"), "")
@@ -781,14 +781,14 @@ string multiteam_info_sprintf(string input, string teamname) { return ((input !=
 
     MSG_CENTER_NOTIF(TIMEOUT_BEGINNING,                 N_ENABLE,    0, 1, "",               CPID_TIMEOUT,           "1 f1", _("^F4Timeout begins in ^COUNT"), "")
     MSG_CENTER_NOTIF(TIMEOUT_ENDING,                    N_ENABLE,    0, 1, "",               CPID_TIMEIN,            "1 f1", _("^F4Timeout ends in ^COUNT"), "")
-    //LegendGuard adds MSG_CENTER_NOTIF for TTT 20-02-2021
-    MSG_CENTER_NOTIF(TTT_TRAITOR,                       N_ENABLE,    0, 0, "",               CPID_TTT,               "5 0",  strcat(BOLD_OPERATOR, _("^BGYou are ^K1Traitor^BG! Kill all the innocents without raising suspicion!")), "")
-    MSG_CENTER_NOTIF(TTT_TRAITOR_WIN,                   N_ENABLE,    0, 0, "",               CPID_ROUND,             "0 0",  _("^K1Traitors^BG win the round"), "")
+    //LegendGuard adds MSG_CENTER_NOTIF for MMM 20-02-2021
+    MSG_CENTER_NOTIF(MMM_MURDERER,                      N_ENABLE,    0, 0, "",               CPID_MMM,               "5 0",  strcat(BOLD_OPERATOR, _("^BGYou are ^K1Murderer^BG! Kill all the civilians without raising suspicion!")), "")
+    MSG_CENTER_NOTIF(MMM_MURDERER_WIN,                  N_ENABLE,    0, 0, "",               CPID_ROUND,             "0 0",  _("^K1Murderers^BG win the round"), "")
     
-    MSG_CENTER_NOTIF(TTT_INNOCENT,                      N_ENABLE,    0, 0, "",               CPID_TTT,               "5 0",  strcat(BOLD_OPERATOR, _("^BGYou are ^F1Innocent^BG! Try to find out who are traitors and survive until time is up!")), "")
-    MSG_CENTER_NOTIF(TTT_INNOCENT_WIN,                  N_ENABLE,    0, 0, "",               CPID_ROUND,             "0 0",  _("^F1Innocents^BG win the round"), "")
+    MSG_CENTER_NOTIF(MMM_CIVILIAN,                      N_ENABLE,    0, 0, "",               CPID_MMM,               "5 0",  strcat(BOLD_OPERATOR, _("^BGYou are ^F1Civilian^BG! Try to find out who are murderers and survive until time is up!")), "")
+    MSG_CENTER_NOTIF(MMM_CIVILIAN_WIN,                  N_ENABLE,    0, 0, "",               CPID_ROUND,             "0 0",  _("^F1Civilians^BG win the round"), "")
     
-    MSG_CENTER_NOTIF(TTT_DETECTIVE,                     N_ENABLE,    0, 0, "",               CPID_TTT,               "5 0",  strcat(BOLD_OPERATOR, _("^BGYou are ^4Detective^BG! Find out who are traitors and protect the innocents!")), "")
+    MSG_CENTER_NOTIF(MMM_SLEUTH,                        N_ENABLE,    0, 0, "",               CPID_MMM,               "5 0",  strcat(BOLD_OPERATOR, _("^BGYou are ^4Sleuth^BG! Find out who are murderers and protect the civilians!")), "")
 
     MSG_CENTER_NOTIF(JOIN_PREVENT_MINIGAME,             N_ENABLE,    0, 0, "",               CPID_Null,              "0 0",  _("^K1Cannot join given minigame session!"), "" )
 
index 8c921055af609ce4e7445366f8a1595299e30bb7..64b11c7be7906494718a5c69e655644d4b2d4827 100644 (file)
@@ -40,7 +40,7 @@ string Get_Notif_TypeName(MSG net_type)
        LOG_WARNF("Get_Notif_TypeName(%d): Improper net type!", ORDINAL(net_type));
        return "";
 }
-//LegendGuard adds CASE(CPID, TTT) after TIMEIN for TTT 20-02-2021
+//LegendGuard adds CASE(CPID, MMM) after TIMEIN for MMM 20-02-2021
 ENUMCLASS(CPID)
        CASE(CPID, ASSAULT_ROLE)
        CASE(CPID, ROUND)
@@ -72,7 +72,7 @@ ENUMCLASS(CPID)
        CASE(CPID, TEAMCHANGE)
        CASE(CPID, TIMEOUT)
        CASE(CPID, TIMEIN)
-       CASE(CPID, TTT)
+       CASE(CPID, MMM)
        CASE(CPID, VEHICLES)
        CASE(CPID, VEHICLES_OTHER)
        /** always last */
index c64eeaf897acc32d5fed93d6b162cfe3fd17bff9..8e1d8e61cbb79da1582ee4e68cd7c18215cfa5f4 100644 (file)
@@ -86,8 +86,7 @@ REGISTER_SP(NEXBALL_FAULTS);
 REGISTER_SP(ONS_TAKES);
 REGISTER_SP(ONS_CAPS);
 
-REGISTER_SP(TTT_RESISTS); //LegendGuard adds REGISTER_SP for TTT 20-02-2021 //Innocents as number of suvivals
-REGISTER_SP(TTT_KARMA); //LegendGuard adds REGISTER_SP for TTT Karma points 21-02-2021
+REGISTER_SP(MMM_KARMA); //LegendGuard adds REGISTER_SP for MMM Karma points 21-02-2021
 #endif
 
 
index 880b378c84aefb4b80b652e2ba8ca733a52609c3..2ce953cd5984b6d0ca01d83238ac333076f13947 100644 (file)
@@ -435,4 +435,4 @@ REGISTER_STAT(GUNALIGN, int)
 SPECTATE_COPYFIELD(_STAT(GUNALIGN))
 #endif
 
-REGISTER_STAT(TTT_ROUNDTIMER, float) //LegendGuard adds TTT_ROUNDTIMER for TTT 20-02-2021
+REGISTER_STAT(MMM_ROUNDTIMER, float) //LegendGuard adds MMM_ROUNDTIMER for MMM 20-02-2021
index 5a98716bde92199d711a03e743d71b818c919c02..39a26956be6877498b63f95bdac02bf15359d08d 100644 (file)
@@ -683,8 +683,8 @@ float updateCompression()
        GAMETYPE(MAPINFO_TYPE_ASSAULT) \
        /* GAMETYPE(MAPINFO_TYPE_DUEL) */ \
        /* GAMETYPE(MAPINFO_TYPE_INVASION) */ \
-       GAMETYPE(MAPINFO_TYPE_TTT) \
-       //LegendGuard adds GAMETYPE for menu for TTT 20-02-2021
+       GAMETYPE(MAPINFO_TYPE_MMM) \
+       //LegendGuard adds GAMETYPE for menu for MMM 20-02-2021
        /**/
 
 // hidden gametypes come last so indexing always works correctly
index 91cb13810a1e6e6bf3fac3033f2902bdf2bc4a1b..7f8d1e990f6c9d9d56bc5b9e04a57f810e295fff 100644 (file)
@@ -301,8 +301,8 @@ void cvar_changes_init()
                BADCVAR("g_tdm");
                BADCVAR("g_tdm_on_dm_maps");
                BADCVAR("g_tdm_teams");
-               BADCVAR("g_ttt");
-               BADCVAR("g_ttt_not_dm_maps");
+               BADCVAR("g_mmm");
+               BADCVAR("g_mmm_not_dm_maps");
                BADCVAR("g_vip");
                BADCVAR("leadlimit");
                BADCVAR("nextmap");
@@ -312,7 +312,7 @@ void cvar_changes_init()
                BADCVAR("g_mapinfo_ignore_warnings");
                BADCVAR("g_maplist_ignore_sizes");
                BADCVAR("g_maplist_sizes_count_bots");
-               //LegendGuard adds BADCVAR(g_*) for TTT 20-02-2021
+               //LegendGuard adds BADCVAR(g_*) for MMM 20-02-2021
 
                // long
                BADCVAR("hostname");