]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Merge branch 'master' into drjaska/mayhem
authordrjaska <drjaska83@gmail.com>
Tue, 18 Jan 2022 21:41:27 +0000 (23:41 +0200)
committerdrjaska <drjaska83@gmail.com>
Tue, 18 Jan 2022 21:41:27 +0000 (23:41 +0200)
33 files changed:
balance-mario.cfg
balance-nexuiz25.cfg
balance-overkill.cfg
balance-samual.cfg
balance-xdf.cfg
balance-xonotic.cfg
balance-xpm.cfg
gamemodes-client.cfg
gamemodes-server.cfg
gfx/menu/luma/gametype_mayhem.tga [new file with mode: 0644]
gfx/menu/luma/gametype_tmayhem.tga [new file with mode: 0644]
gfx/menu/luminos/gametype_mayhem.tga [new file with mode: 0644]
gfx/menu/luminos/gametype_tmayhem.tga [new file with mode: 0644]
gfx/menu/wickedx/gametype_mayhem.tga [new file with mode: 0644]
gfx/menu/wickedx/gametype_tmayhem.tga [new file with mode: 0644]
gfx/menu/xaw/gametype_mayhem.tga [new file with mode: 0644]
gfx/menu/xaw/gametype_tmayhem.tga [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/_mod.inc
qcsrc/common/gamemodes/gamemode/_mod.qh
qcsrc/common/gamemodes/gamemode/mayhem/_mod.inc [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/mayhem/_mod.qh [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/mayhem/mayhem.qc [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/mayhem/mayhem.qh [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/mayhem/sv_mayhem.qc [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/mayhem/sv_mayhem.qh [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/tmayhem/_mod.inc [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/tmayhem/_mod.qh [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/tmayhem/sv_tmayhem.qc [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/tmayhem/sv_tmayhem.qh [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/tmayhem/tmayhem.qc [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/tmayhem/tmayhem.qh [new file with mode: 0644]
qcsrc/menu/xonotic/util.qc
qcsrc/server/world.qc

index 42e3a66967db0f6d958a220c9a9e6425c1683f1d..8b9f37ac10d7782c60f1248aef0e82feb4cd2c5f 100644 (file)
@@ -49,6 +49,22 @@ set g_lms_start_ammo_rockets 160
 set g_lms_start_ammo_cells 180
 set g_lms_start_ammo_plasma 180
 set g_lms_start_ammo_fuel 0
+set g_mayhem_start_health 200
+set g_mayhem_start_armor 200
+set g_mayhem_start_ammo_shells 60
+set g_mayhem_start_ammo_nails 320
+set g_mayhem_start_ammo_rockets 160
+set g_mayhem_start_ammo_cells 180
+set g_mayhem_start_ammo_plasma 180
+set g_mayhem_start_ammo_fuel 0
+set g_tmayhem_start_health 200
+set g_tmayhem_start_armor 200
+set g_tmayhem_start_ammo_shells 60
+set g_tmayhem_start_ammo_nails 320
+set g_tmayhem_start_ammo_rockets 160
+set g_tmayhem_start_ammo_cells 180
+set g_tmayhem_start_ammo_plasma 180
+set g_tmayhem_start_ammo_fuel 0
 set g_balance_nix_roundtime 25
 set g_balance_nix_incrtime 1.6
 set g_balance_nix_ammo_shells 60
index 6cdc29dcc4deec4152bd1e8f985cf87630e90de9..0b39de222f3a3305f0836801995204cdcbfe45db 100644 (file)
@@ -49,6 +49,22 @@ set g_lms_start_ammo_rockets 50
 set g_lms_start_ammo_cells 50
 set g_lms_start_ammo_plasma 50
 set g_lms_start_ammo_fuel 0
+set g_mayhem_start_health 250
+set g_mayhem_start_armor 100
+set g_mayhem_start_ammo_shells 50
+set g_mayhem_start_ammo_nails 150
+set g_mayhem_start_ammo_rockets 50
+set g_mayhem_start_ammo_cells 50
+set g_mayhem_start_ammo_plasma 50
+set g_mayhem_start_ammo_fuel 0
+set g_tmayhem_start_health 250
+set g_tmayhem_start_armor 100
+set g_tmayhem_start_ammo_shells 50
+set g_tmayhem_start_ammo_nails 150
+set g_tmayhem_start_ammo_rockets 50
+set g_tmayhem_start_ammo_cells 50
+set g_tmayhem_start_ammo_plasma 50
+set g_tmayhem_start_ammo_fuel 0
 set g_balance_nix_roundtime 25
 set g_balance_nix_incrtime 1.6
 set g_balance_nix_ammo_shells 15
index e33ee827f66699289c388db8bd38351d4e8c8ccf..3944d7d3b18ab87d6cc280e38df1c23360bf912f 100644 (file)
@@ -49,6 +49,22 @@ set g_lms_start_ammo_rockets 160
 set g_lms_start_ammo_cells 180
 set g_lms_start_ammo_plasma 180
 set g_lms_start_ammo_fuel 0
+set g_mayhem_start_health 200
+set g_mayhem_start_armor 100
+set g_mayhem_start_ammo_shells 60
+set g_mayhem_start_ammo_nails 320
+set g_mayhem_start_ammo_rockets 160
+set g_mayhem_start_ammo_cells 180
+set g_mayhem_start_ammo_plasma 180
+set g_mayhem_start_ammo_fuel 0
+set g_tmayhem_start_health 200
+set g_tmayhem_start_armor 100
+set g_tmayhem_start_ammo_shells 60
+set g_tmayhem_start_ammo_nails 320
+set g_tmayhem_start_ammo_rockets 160
+set g_tmayhem_start_ammo_cells 180
+set g_tmayhem_start_ammo_plasma 180
+set g_tmayhem_start_ammo_fuel 0
 set g_balance_nix_roundtime 25
 set g_balance_nix_incrtime 1.6
 set g_balance_nix_ammo_shells 60
index 7850aaba8b97eac07e8c77dce3ee632d85433a09..5686c58d6e24fa2eb211af18644d7ecd536986b6 100644 (file)
@@ -49,6 +49,22 @@ set g_lms_start_ammo_rockets 160
 set g_lms_start_ammo_cells 180
 set g_lms_start_ammo_plasma 180
 set g_lms_start_ammo_fuel 0
+set g_mayhem_start_health 200
+set g_mayhem_start_armor 200
+set g_mayhem_start_ammo_shells 60
+set g_mayhem_start_ammo_nails 320
+set g_mayhem_start_ammo_rockets 160
+set g_mayhem_start_ammo_cells 180
+set g_mayhem_start_ammo_plasma 180
+set g_mayhem_start_ammo_fuel 0
+set g_tmayhem_start_health 200
+set g_tmayhem_start_armor 200
+set g_tmayhem_start_ammo_shells 60
+set g_tmayhem_start_ammo_nails 320
+set g_tmayhem_start_ammo_rockets 160
+set g_tmayhem_start_ammo_cells 180
+set g_tmayhem_start_ammo_plasma 180
+set g_tmayhem_start_ammo_fuel 0
 set g_balance_nix_roundtime 25
 set g_balance_nix_incrtime 1.6
 set g_balance_nix_ammo_shells 60
index 94e98a6461ccc1f85ded776b3bd7685f9c6f71ad..f248b7ac83a46d151e279f13da416924505a1c60 100644 (file)
@@ -49,6 +49,22 @@ set g_lms_start_ammo_rockets 160
 set g_lms_start_ammo_cells 180
 set g_lms_start_ammo_plasma 180
 set g_lms_start_ammo_fuel 0
+set g_mayhem_start_health 200
+set g_mayhem_start_armor 200
+set g_mayhem_start_ammo_shells 60
+set g_mayhem_start_ammo_nails 320
+set g_mayhem_start_ammo_rockets 160
+set g_mayhem_start_ammo_cells 180
+set g_mayhem_start_ammo_plasma 180
+set g_mayhem_start_ammo_fuel 0
+set g_tmayhem_start_health 200
+set g_tmayhem_start_armor 200
+set g_tmayhem_start_ammo_shells 60
+set g_tmayhem_start_ammo_nails 320
+set g_tmayhem_start_ammo_rockets 160
+set g_tmayhem_start_ammo_cells 180
+set g_tmayhem_start_ammo_plasma 180
+set g_tmayhem_start_ammo_fuel 0
 set g_balance_nix_roundtime 25
 set g_balance_nix_incrtime 1.6
 set g_balance_nix_ammo_shells 60
index 784e447f418137208402e10d7b9cd2a99c974621..2cf8c9eb4269b106877384494b4a6392c3200fc4 100644 (file)
@@ -49,6 +49,22 @@ set g_lms_start_ammo_rockets 160
 set g_lms_start_ammo_cells 180
 set g_lms_start_ammo_plasma 180
 set g_lms_start_ammo_fuel 0
+set g_mayhem_start_health 200
+set g_mayhem_start_armor 200
+set g_mayhem_start_ammo_shells 60
+set g_mayhem_start_ammo_nails 320
+set g_mayhem_start_ammo_rockets 160
+set g_mayhem_start_ammo_cells 180
+set g_mayhem_start_ammo_plasma 180
+set g_mayhem_start_ammo_fuel 0
+set g_tmayhem_start_health 200
+set g_tmayhem_start_armor 200
+set g_tmayhem_start_ammo_shells 60
+set g_tmayhem_start_ammo_nails 320
+set g_tmayhem_start_ammo_rockets 160
+set g_tmayhem_start_ammo_cells 180
+set g_tmayhem_start_ammo_plasma 180
+set g_tmayhem_start_ammo_fuel 0
 set g_balance_nix_roundtime 25
 set g_balance_nix_incrtime 1.6
 set g_balance_nix_ammo_shells 60
index 189be9c718544d7eb19e52dc8d67329c6df49e39..87b781a555216639bb618652be91097abfe09e62 100644 (file)
@@ -49,6 +49,22 @@ set g_lms_start_ammo_rockets 160
 set g_lms_start_ammo_cells 180
 set g_lms_start_ammo_plasma 180
 set g_lms_start_ammo_fuel 0
+set g_mayhem_start_health 200
+set g_mayhem_start_armor 200
+set g_mayhem_start_ammo_shells 60
+set g_mayhem_start_ammo_nails 320
+set g_mayhem_start_ammo_rockets 160
+set g_mayhem_start_ammo_cells 180
+set g_mayhem_start_ammo_plasma 180
+set g_mayhem_start_ammo_fuel 0
+set g_tmayhem_start_health 200
+set g_tmayhem_start_armor 200
+set g_tmayhem_start_ammo_shells 60
+set g_tmayhem_start_ammo_nails 320
+set g_tmayhem_start_ammo_rockets 160
+set g_tmayhem_start_ammo_cells 180
+set g_tmayhem_start_ammo_plasma 180
+set g_tmayhem_start_ammo_fuel 0
 set g_balance_nix_roundtime 25
 set g_balance_nix_incrtime 1.6
 set g_balance_nix_ammo_shells 60
index c43b9d1d3f2e6fe73fddbb33e8489670350edc4d..c3dd709127ca53dc9b0216f654d9f1548599120e 100644 (file)
@@ -32,6 +32,8 @@ alias cl_hook_gamestart_ka
 alias cl_hook_gamestart_ft
 alias cl_hook_gamestart_inv
 alias cl_hook_gamestart_duel
+alias cl_hook_gamestart_mayhem
+alias cl_hook_gamestart_tmayhem
 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 62570e5239e86bbd3b749efe7b20b036d67abec2..d86eb141d7e2cf4ed415c6db66447228425e6156 100644 (file)
@@ -29,6 +29,8 @@ alias sv_hook_gamestart_ka
 alias sv_hook_gamestart_ft
 alias sv_hook_gamestart_inv
 alias sv_hook_gamestart_duel
+alias sv_hook_gamestart_mayhem
+alias sv_hook_gamestart_tmayhem
 // 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
@@ -58,6 +60,8 @@ 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_mayhem
+alias sv_vote_gametype_hook_tmayhem
 
 // 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.
@@ -208,6 +212,20 @@ 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_mayhem_respawn_delay_small 0
+set g_mayhem_respawn_delay_small_count 0
+set g_mayhem_respawn_delay_large 0
+set g_mayhem_respawn_delay_large_count 0
+set g_mayhem_respawn_delay_max 0
+set g_mayhem_respawn_waves 0
+set g_mayhem_weapon_stay 0
+set g_tmayhem_respawn_delay_small 0
+set g_tmayhem_respawn_delay_small_count 0
+set g_tmayhem_respawn_delay_large 0
+set g_tmayhem_respawn_delay_large_count 0
+set g_tmayhem_respawn_delay_max 0
+set g_tmayhem_respawn_waves 0
+set g_tmayhem_weapon_stay 0
 
 
 // =========
@@ -560,3 +578,46 @@ set g_duel 0 "Duel: frag the opponent more in a one versus one arena battle"
 //set g_duel_warmup 180 "Have a short warmup period before beginning the actual duel"
 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"
+
+// ==============================
+//  free for all and team mayhem
+// ==============================
+set g_mayhem 0 "Mayhem: Compete for the most damage dealt and frags in this chaotic mayhem!"
+set g_tmayhem 0 "Team Mayhem: Compete with your team for the most damage dealt and frags in this chaotic mayhem!"
+
+set g_mayhem_scoringmethod 1 "1: By default 25% of the score is based on kills and 75% of it is based on damage. 2: 100% frags. 3: 100% damage."
+set g_tmayhem_scoringmethod 1 "1: By default 25% of the score is based on kills and 75% of it is based on damage. 2: 100% frags. 3: 100% damage."
+set g_mayhem_scoringmethod_1_damage_weight 0.75 "for the first scoring method how much is damage equal to player's spawning health worth in score"
+set g_tmayhem_scoringmethod_1_damage_weight 0.75 "for the first scoring method how much is damage equal to player's spawning health worth in score"
+set g_mayhem_scoringmethod_1_disable_selfdamage2score 0 "disable reducing score with self damage at the cost of full penalty for suicides regardless of how much health was lost suiciding"
+set g_tmayhem_scoringmethod_1_disable_selfdamage2score 0 "disable reducing score with self damage at the cost of full penalty for suicides regardless of how much health was lost suiciding"
+set g_mayhem_scoringmethod_1_frag_weight 0.25 "for the first scoring method how much is a frag worth in score"
+set g_tmayhem_scoringmethod_1_frag_weight 0.25 "for the first scoring method how much is a frag worth in score"
+
+set g_mayhem_fraglimit 30 "Team Mayhem basis for how many frags until the match ends, edit this over point_limit preferably"
+set g_tmayhem_fraglimit 50 "Team Mayhem basis for how many frags until the match ends, edit this over point_limit preferably"
+
+set g_mayhem_visual_score_limit 1000 "Mayhem visual score limit overriding the mapinfo specified one"
+set g_tmayhem_visual_score_limit 1000 "Team Mayhem visual score limit overriding the mapinfo specified one"
+
+set g_tmayhem_score_leadlimit -1 "Team Mayhem score lead limit(based on tmayhem_visual_score_limit, not tmayhem_fraglimit) overriding the mapinfo specified one (use 0 to play without limit, and -1 to use the mapinfo's limit)"
+
+set g_mayhem_weaponarena "most_available" "starting weapons - takes the same options as g_weaponarena"
+set g_tmayhem_weaponarena "most_available" "starting weapons - takes the same options as g_weaponarena"
+
+set g_mayhem_powerups 1 "Allow powerups in mayhem. Only checked if g_powerups is -1 therefore this will be overridden by g_powerups 1 or 0"
+set g_tmayhem_powerups 1 "Allow powerups in team mayhem. Only checked if g_powerups is -1 therefore this will be overridden by g_powerups 1 or 0"
+set g_mayhem_pickup_items 0 "spawn pickup items in mayhem"
+set g_tmayhem_pickup_items 0 "spawn pickup items in team mayhem"
+set g_mayhem_pickup_items_remove_weapons_and_ammo 1 "when pickup items are enabled in mayhem still remove weapons and ammo pickups"
+set g_tmayhem_pickup_items_remove_weapons_and_ammo 1 "when pickup items are enabled in team mayhem still remove weapons and ammo pickups"
+
+set g_mayhem_selfdamage 0 "0 = disable selfdamage in mayhem, 1 = enable selfdamage in mayhem"
+set g_tmayhem_selfdamage 0 "0 = disable selfdamage in tmayhem, 1 = enable selfdamage in tmayhem"
+
+set g_mayhem_regenerate 0 "allow players to regenerate hp. rates controlled by hp regeneration and rotting cvars"
+set g_tmayhem_regenerate 0 "allow players to regenerate hp. rates controlled by hp regeneration and rotting cvars"
+
+set g_tmayhem_teams 2 "how many teams are in team mayhem (set by mapinfo)"
+set g_tmayhem_team_spawns 0 "when 1, players spawn from the team spawnpoints of the map, if any"
+set g_tmayhem_teams_override 0 "how many teams are in team mayhem"
diff --git a/gfx/menu/luma/gametype_mayhem.tga b/gfx/menu/luma/gametype_mayhem.tga
new file mode 100644 (file)
index 0000000..bcd8bb5
Binary files /dev/null and b/gfx/menu/luma/gametype_mayhem.tga differ
diff --git a/gfx/menu/luma/gametype_tmayhem.tga b/gfx/menu/luma/gametype_tmayhem.tga
new file mode 100644 (file)
index 0000000..1b4f70d
Binary files /dev/null and b/gfx/menu/luma/gametype_tmayhem.tga differ
diff --git a/gfx/menu/luminos/gametype_mayhem.tga b/gfx/menu/luminos/gametype_mayhem.tga
new file mode 100644 (file)
index 0000000..cd7e57d
Binary files /dev/null and b/gfx/menu/luminos/gametype_mayhem.tga differ
diff --git a/gfx/menu/luminos/gametype_tmayhem.tga b/gfx/menu/luminos/gametype_tmayhem.tga
new file mode 100644 (file)
index 0000000..8def1e5
Binary files /dev/null and b/gfx/menu/luminos/gametype_tmayhem.tga differ
diff --git a/gfx/menu/wickedx/gametype_mayhem.tga b/gfx/menu/wickedx/gametype_mayhem.tga
new file mode 100644 (file)
index 0000000..cd7e57d
Binary files /dev/null and b/gfx/menu/wickedx/gametype_mayhem.tga differ
diff --git a/gfx/menu/wickedx/gametype_tmayhem.tga b/gfx/menu/wickedx/gametype_tmayhem.tga
new file mode 100644 (file)
index 0000000..8def1e5
Binary files /dev/null and b/gfx/menu/wickedx/gametype_tmayhem.tga differ
diff --git a/gfx/menu/xaw/gametype_mayhem.tga b/gfx/menu/xaw/gametype_mayhem.tga
new file mode 100644 (file)
index 0000000..b392973
Binary files /dev/null and b/gfx/menu/xaw/gametype_mayhem.tga differ
diff --git a/gfx/menu/xaw/gametype_tmayhem.tga b/gfx/menu/xaw/gametype_tmayhem.tga
new file mode 100644 (file)
index 0000000..08e8a97
Binary files /dev/null and b/gfx/menu/xaw/gametype_tmayhem.tga differ
index a33ec87a01a34a5a8406f57aa3c3d52829cf3994..b106ec9ace5dca99e7cc42607b644bd3a0e8528f 100644 (file)
@@ -12,7 +12,9 @@
 #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/mayhem/_mod.inc>
 #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/tdm/_mod.inc>
+#include <common/gamemodes/gamemode/tmayhem/_mod.inc>
\ No newline at end of file
index ffd71d59d3f1092453b6d83f8048003693dfa531..15b6ecaac71096e1f63f9e7a939674538a9e6a8c 100644 (file)
@@ -12,7 +12,9 @@
 #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/mayhem/_mod.qh>
 #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/tdm/_mod.qh>
+#include <common/gamemodes/gamemode/tmayhem/_mod.qh>
\ No newline at end of file
diff --git a/qcsrc/common/gamemodes/gamemode/mayhem/_mod.inc b/qcsrc/common/gamemodes/gamemode/mayhem/_mod.inc
new file mode 100644 (file)
index 0000000..37daedb
--- /dev/null
@@ -0,0 +1,5 @@
+// generated file; do not modify
+#include <common/gamemodes/gamemode/mayhem/mayhem.qc>
+#ifdef SVQC
+    #include <common/gamemodes/gamemode/mayhem/sv_mayhem.qc>
+#endif
diff --git a/qcsrc/common/gamemodes/gamemode/mayhem/_mod.qh b/qcsrc/common/gamemodes/gamemode/mayhem/_mod.qh
new file mode 100644 (file)
index 0000000..abe1980
--- /dev/null
@@ -0,0 +1,5 @@
+// generated file; do not modify
+#include <common/gamemodes/gamemode/mayhem/mayhem.qh>
+#ifdef SVQC
+    #include <common/gamemodes/gamemode/mayhem/sv_mayhem.qh>
+#endif
diff --git a/qcsrc/common/gamemodes/gamemode/mayhem/mayhem.qc b/qcsrc/common/gamemodes/gamemode/mayhem/mayhem.qc
new file mode 100644 (file)
index 0000000..6af7428
--- /dev/null
@@ -0,0 +1 @@
+#include "mayhem.qh"
diff --git a/qcsrc/common/gamemodes/gamemode/mayhem/mayhem.qh b/qcsrc/common/gamemodes/gamemode/mayhem/mayhem.qh
new file mode 100644 (file)
index 0000000..e853d35
--- /dev/null
@@ -0,0 +1,33 @@
+#pragma once
+
+#include <common/gamemodes/gamemode/deathmatch/deathmatch.qh>
+#include <common/gamemodes/gamemode/tdm/tdm.qh>
+#include <common/mapinfo.qh>
+
+CLASS(mayhem, Gametype)
+    INIT(mayhem)
+    {
+        this.gametype_init(this, _("Mayhem"),"mayhem","g_mayhem",GAMETYPE_FLAG_USEPOINTS | GAMETYPE_FLAG_PREFERRED,"","timelimit=15 pointlimit=30 leadlimit=0",_("Compete for the most damage dealt and frags in this chaotic mayhem!"));
+    }
+    METHOD(mayhem, m_isAlwaysSupported, bool(Gametype this, int spawnpoints, float diameter))
+    {
+        return true;
+    }
+    METHOD(mayhem, m_isForcedSupported, bool(Gametype this))
+    {
+        if(!(MapInfo_Map_supportedGametypes & this.m_flags) && (MapInfo_Map_supportedGametypes & MAPINFO_TYPE_DEATHMATCH.m_flags)){
+               return true;
+        }
+        if(!(MapInfo_Map_supportedGametypes & this.m_flags) && (MapInfo_Map_supportedGametypes & MAPINFO_TYPE_TEAM_DEATHMATCH.m_flags)){
+               return true;
+        }
+        return false;          
+    }
+       METHOD(mayhem, m_configuremenu, void(Gametype this, entity menu, void(entity me, string pLabel, float pMin, float pMax, float pStep, string pCvar, string tCvar, string pTooltip) returns))
+    {
+        TC(Gametype, this);
+        returns(menu, _("Frag limit:"),     5,  100,  5, "g_mayhem_fraglimit",         string_null,         _("How many frags worth of score is needed before the match will end"));
+    }
+    ATTRIB(mayhem, m_legacydefaults, string, "30 20 0");
+ENDCLASS(mayhem)
+REGISTER_GAMETYPE(MAYHEM, NEW(mayhem));
diff --git a/qcsrc/common/gamemodes/gamemode/mayhem/sv_mayhem.qc b/qcsrc/common/gamemodes/gamemode/mayhem/sv_mayhem.qc
new file mode 100644 (file)
index 0000000..7a8ae68
--- /dev/null
@@ -0,0 +1,299 @@
+#include "sv_mayhem.qh"
+#include <common/scores.qh>
+
+float autocvar_g_mayhem_fraglimit;
+float autocvar_g_mayhem_visual_score_limit;
+float mayhempointmultiplier;
+
+bool autocvar_g_mayhem_regenerate;
+string autocvar_g_mayhem_weaponarena;
+bool autocvar_g_mayhem_powerups;
+bool autocvar_g_mayhem_selfdamage;
+int autocvar_g_mayhem_scoringmethod;
+float autocvar_g_mayhem_scoringmethod_1_damage_weight;
+float autocvar_g_mayhem_scoringmethod_1_frag_weight;
+bool autocvar_g_mayhem_scoringmethod_1_disable_selfdamage2score;
+bool autocvar_g_mayhem_pickup_items;
+bool autocvar_g_mayhem_pickup_items_remove_weapons_and_ammo;
+bool autocvar_g_mayhem_unlimited_ammo;
+
+float autocvar_g_mayhem_start_health = 200;
+float autocvar_g_mayhem_start_armor = 200;
+float autocvar_g_mayhem_start_ammo_shells = 60;
+float autocvar_g_mayhem_start_ammo_nails = 320;
+float autocvar_g_mayhem_start_ammo_rockets = 160;
+float autocvar_g_mayhem_start_ammo_cells = 180;
+float autocvar_g_mayhem_start_ammo_plasma = 180;
+float autocvar_g_mayhem_start_ammo_fuel = 0;
+
+.float total_damage_dealt;
+
+void mayhem_DelayedInit(entity this)
+{
+       return;
+}
+
+void mayhem_Initialize()
+{
+       if(autocvar_g_mayhem_visual_score_limit > 0 && autocvar_g_mayhem_fraglimit > 0)
+               mayhempointmultiplier = autocvar_g_mayhem_visual_score_limit / autocvar_g_mayhem_fraglimit;
+
+       GameRules_limit_score(autocvar_g_mayhem_visual_score_limit);
+
+       InitializeEntity(NULL, mayhem_DelayedInit, INITPRIO_GAMETYPE);
+}
+
+MUTATOR_HOOKFUNCTION(mayhem, Scores_CountFragsRemaining)
+{
+       // announce remaining frags
+       return true;
+}
+
+MUTATOR_HOOKFUNCTION(mayhem, SetStartItems)
+{
+       start_items       &= ~(IT_UNLIMITED_AMMO | IT_UNLIMITED_SUPERWEAPONS);
+       if(!cvar("g_use_ammunition") || autocvar_g_mayhem_unlimited_ammo)
+               start_items |= IT_UNLIMITED_AMMO;
+
+       start_health       = warmup_start_health       = autocvar_g_mayhem_start_health;
+       start_armorvalue   = warmup_start_armorvalue   = autocvar_g_mayhem_start_armor;
+       start_ammo_shells  = warmup_start_ammo_shells  = autocvar_g_mayhem_start_ammo_shells;
+       start_ammo_nails   = warmup_start_ammo_nails   = autocvar_g_mayhem_start_ammo_nails;
+       start_ammo_rockets = warmup_start_ammo_rockets = autocvar_g_mayhem_start_ammo_rockets;
+       start_ammo_cells   = warmup_start_ammo_cells   = autocvar_g_mayhem_start_ammo_cells;
+       start_ammo_plasma  = warmup_start_ammo_plasma  = autocvar_g_mayhem_start_ammo_plasma;
+       start_ammo_fuel    = warmup_start_ammo_fuel    = autocvar_g_mayhem_start_ammo_fuel;
+}
+
+//this hook also enables rotting, as players spawn with more hp and armor than what default rot limits are set to this is a bad idea as of now
+MUTATOR_HOOKFUNCTION(mayhem, PlayerRegen)
+{
+       if(autocvar_g_mayhem_regenerate)
+               return false;
+       return true;
+}
+
+MUTATOR_HOOKFUNCTION(mayhem, ForbidThrowCurrentWeapon)
+{
+       return true;
+}
+
+MUTATOR_HOOKFUNCTION(mayhem, SetWeaponArena)
+{
+       if (M_ARGV(0, string) == "0" || M_ARGV(0, string) == "")
+               M_ARGV(0, string) = autocvar_g_mayhem_weaponarena;
+}
+
+MUTATOR_HOOKFUNCTION(mayhem, FilterItem)
+{
+       entity item = M_ARGV(0, entity);
+       
+       //enable powerups if forced globally or global accepts gamemodes to have powerups according to their own settings
+       if (autocvar_g_powerups == 1 || (autocvar_g_powerups == -1 && autocvar_g_mayhem_powerups == 1)){
+               if (item.itemdef.instanceOfPowerup){
+                       return false;
+               } 
+       }
+       //disabled powerups if forced off globally or in this gamemode
+       if (autocvar_g_powerups == 0 || autocvar_g_mayhem_powerups == 0){
+               if (item.itemdef.instanceOfPowerup){
+                       return true; 
+               } 
+       }
+       //remove all items if items are forced off globally
+       if (autocvar_g_pickup_items == 0){
+               return true;
+       }
+       //if items are switched on in this gamemode allow the removal of weapons and ammo still
+       if ((autocvar_g_mayhem_pickup_items == 1 && autocvar_g_mayhem_pickup_items_remove_weapons_and_ammo == 1) && autocvar_g_pickup_items <= 0){
+               if (item.itemdef.instanceOfAmmo || item.itemdef.instanceOfWeaponPickup){
+                       return true;
+               }
+       }
+       //remove items if not globally set to follow mode's settings and locally set off
+       if (autocvar_g_pickup_items == -1 && autocvar_g_mayhem_pickup_items == 0){
+               return true;
+       }
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(mayhem, Damage_Calculate)
+{
+       entity frag_attacker = M_ARGV(1, entity);
+       entity frag_target = M_ARGV(2, entity);
+       float frag_deathtype = M_ARGV(3, float);
+       float frag_damage = M_ARGV(4, float);
+
+       if ((autocvar_g_mayhem_selfdamage == 0 && frag_target == frag_attacker) || frag_deathtype == DEATH_FALL.m_id)
+               frag_damage = 0;
+
+       M_ARGV(4, float) = frag_damage;
+}
+
+void FFAMayhemCalculatePlayerScore(entity scorer){
+       switch (autocvar_g_mayhem_scoringmethod)
+       {
+               default:
+               case 1:
+               {
+                       //calculate how much score the player should have based on their damage dealt and frags gotten and then add the missing score
+
+                       //give a different weight for suicides if scoring method 1 doesn't have selfdamage2score enabled to harshly punish for suicides to avoid exploiting
+                       float suicide_weight = 1 + (autocvar_g_mayhem_scoringmethod_1_disable_selfdamage2score * (1/autocvar_g_mayhem_scoringmethod_1_frag_weight));
+
+                       //total damage divided by player start health&armor to get how many lives worth of damage they've dealt, then how much that is out of the fraglimit, then calculate new value affected by weight
+                       float playerdamagescore = (((((scorer.total_damage_dealt/(start_health + start_armorvalue)) * 100)/autocvar_g_mayhem_fraglimit) * autocvar_g_mayhem_scoringmethod_1_damage_weight) );
+                                                                                                                                                                                                       //  * 100 to avoid float inaccuracy at that decimal level
+
+                       //playerdamagescore rounded
+                       float roundedplayerdamagescore = ((rint(playerdamagescore*10))/10);
+
+                       //kills minus suicides, total out of fraglimit, calculate weight
+                       float playerkillscore = ((((PlayerScore_Get(scorer, SP_KILLS) - (PlayerScore_Get(scorer, SP_SUICIDES) * suicide_weight)) * 100) / autocvar_g_mayhem_fraglimit) * autocvar_g_mayhem_scoringmethod_1_frag_weight);
+                                                                                                                                                                                                                                                               //   * 100 to avoid float inaccuracy at that decimal level
+
+                       //only used for debug print, add killscore and damagescore together
+                       float playerscore = (roundedplayerdamagescore + playerkillscore);
+
+                       //add killscore and damagescore together to get total score and then adjust it to be total out of the visual score limit
+                       float playerscorevisual = ((roundedplayerdamagescore + playerkillscore) * autocvar_g_mayhem_visual_score_limit);
+                                                                                                                                                                                                                                               
+
+                       //calculated how much score the player has and now calculate total of how much they are supposed to have
+                       float scoretoadd = (playerscorevisual - (PlayerScore_Get(scorer, SP_SCORE) * 100));
+                                                                                                                                                                  //  * 100 to avoid float inaccuracy at that decimal level
+
+                       //adjust total score to be what the player is supposed to have
+                       GameRules_scoring_add_team(scorer, SCORE, floor(scoretoadd / 100));
+                                                                                                                                       // / 100 to move back to the decimal level
+
+                       if(0){
+                               //debug printing
+                               if(!IS_BOT_CLIENT(scorer)){
+                                       print(sprintf("%f", scorer.total_damage_dealt),                 " scorer.total_damage_dealt \n");
+                                       print(sprintf("%f", playerdamagescore),                                 " playerdamagescore \n");
+                                       print(sprintf("%f", roundedplayerdamagescore),                  " rounded playerdamagescore \n");
+                                       print(sprintf("%f", playerkillscore),                                   " playerkillscore \n");
+                                       print(sprintf("%f", PlayerScore_Get(scorer, SP_KILLS)), " PlayerScore_Get(scorer, SP_KILLS) \n");
+                                       print(sprintf("%f", playerscore),                                               " playerscore \n");
+                                       print(sprintf("%f", playerscorevisual),                                 " visual playerscore \n");
+                                       print(sprintf("%f", scoretoadd),                                                " scoretoadd \n");
+                                       print(sprintf("%f", PlayerScore_Get(scorer, SP_SCORE)), " PlayerScore_Get(scorer, SP_SCORE) \n \n");
+                               }
+                       }
+               return;
+               }
+
+               case 2:
+               {
+                       //calculate how much score the player should have based on their frags gotten and then add the missing score
+                       float playerkillscore = (((PlayerScore_Get(scorer, SP_KILLS) - PlayerScore_Get(scorer, SP_SUICIDES)) * 100)/ autocvar_g_mayhem_fraglimit);
+                       float playerscorevisual = (playerkillscore * autocvar_g_mayhem_visual_score_limit) / 100;
+                       float scoretoadd = (playerscorevisual - PlayerScore_Get(scorer, SP_SCORE));
+                       GameRules_scoring_add_team(scorer, SCORE, floor(scoretoadd));
+
+                       if(0){
+                               //debug printing
+                               if(!IS_BOT_CLIENT(scorer)){
+                                       print(sprintf("%f", playerkillscore),                                   " playerkillscore \n");
+                                       print(sprintf("%f", PlayerScore_Get(scorer, SP_KILLS)), " PlayerScore_Get(scorer, SP_KILLS) \n");
+                                       print(sprintf("%f", playerscorevisual),                                 " visual playerscore \n");
+                                       print(sprintf("%f", scoretoadd),                                                " scoretoadd \n");
+                                       print(sprintf("%f", PlayerScore_Get(scorer, SP_SCORE)), " PlayerScore_Get(scorer, SP_SCORE) \n \n");
+                               }
+                       }
+               return;
+               }
+
+               case 3:
+               {
+                       //calculate how much score the player should have based on their damage dealt and then add the missing score
+                       float playerdamagescore = (((scorer.total_damage_dealt/(start_health + start_armorvalue)) * 100)/autocvar_g_mayhem_fraglimit);
+                       float roundedplayerdamagescore = ((rint(playerdamagescore*10))/10);
+                       float playerscorevisual = (roundedplayerdamagescore * autocvar_g_mayhem_visual_score_limit);
+                       float scoretoadd = (playerscorevisual - (PlayerScore_Get(scorer, SP_SCORE) * 100));
+                       GameRules_scoring_add_team(scorer, SCORE, floor(scoretoadd / 100));
+
+                       if(0){
+                               //debug printing
+                               if(!IS_BOT_CLIENT(scorer)){
+                                       print(sprintf("%f", scorer.total_damage_dealt),                 " scorer.total_damage_dealt \n");
+                                       print(sprintf("%f", playerdamagescore),                                 " playerdamagescore \n");
+                                       print(sprintf("%f", roundedplayerdamagescore),                  " rounded playerdamagescore \n");
+                                       print(sprintf("%f", playerscorevisual),                                 " visual playerscore \n");
+                                       print(sprintf("%f", scoretoadd),                                                " scoretoadd \n");
+                                       print(sprintf("%f", PlayerScore_Get(scorer, SP_SCORE)), " PlayerScore_Get(scorer, SP_SCORE) \n \n");
+                               }
+                       }
+               return;
+               }
+       }
+}
+
+MUTATOR_HOOKFUNCTION(mayhem, PlayerDamage_SplitHealthArmor)
+{
+       if (autocvar_g_mayhem_scoringmethod==2) return;
+       
+       entity frag_target = M_ARGV(2, entity);
+
+       if (StatusEffects_active(STATUSEFFECT_SpawnShield, frag_target) && autocvar_g_spawnshield_blockdamage >= 1)return;
+       
+       entity frag_attacker = M_ARGV(1, entity);
+       float frag_deathtype = M_ARGV(6, float);
+       float frag_damage = M_ARGV(7, float);
+       float damage_take = bound(0, M_ARGV(4, float), GetResource(frag_target, RES_HEALTH));
+       float damage_save = bound(0, M_ARGV(5, float), GetResource(frag_target, RES_ARMOR));
+       float excess = max(0, frag_damage - damage_take - damage_save);
+       float total = frag_damage - excess;
+
+       if (total == 0) return;
+
+       if (StatusEffects_active(STATUSEFFECT_SpawnShield, frag_target) && autocvar_g_spawnshield_blockdamage < 1)
+               total *= 1 - bound(0, autocvar_g_spawnshield_blockdamage, 1);
+
+       entity scorer = NULL; //entity which needs their score to be updated
+
+       if (IS_PLAYER(frag_attacker))
+       {
+               //non-friendly fire
+               if (frag_target != frag_attacker)
+                       frag_attacker.total_damage_dealt += total;
+
+               //friendly fire aka self damage
+               if (frag_target == frag_attacker && !autocvar_g_mayhem_scoringmethod_1_disable_selfdamage2score)
+                       frag_attacker.total_damage_dealt -= total;
+
+               scorer = frag_attacker;
+       }
+       else
+       {
+               //handle (environmental hazard) suiciding, check first if player has a registered attacker who most likely pushed them there to avoid punishing pushed players as pushers are already rewarded
+               //deathtypes:
+               //kill = suicide, drown = drown in water/liquid, hurttrigger = out of the map void or hurt triggers inside maps like electric sparks
+               //camp = campcheck, lava = lava, slime = slime
+               //team change / rebalance suicides are currently not included
+               if (!autocvar_g_mayhem_scoringmethod_1_disable_selfdamage2score && (
+                       frag_deathtype == DEATH_KILL.m_id ||
+                       frag_deathtype == DEATH_DROWN.m_id ||
+                       frag_deathtype == DEATH_HURTTRIGGER.m_id ||
+                       frag_deathtype == DEATH_CAMP.m_id ||
+                       frag_deathtype == DEATH_LAVA.m_id ||
+                       frag_deathtype == DEATH_SLIME.m_id ||
+                       frag_deathtype == DEATH_SWAMP.m_id))
+                               frag_target.total_damage_dealt -= total;
+
+               scorer = frag_target;
+       }
+
+       FFAMayhemCalculatePlayerScore(scorer);
+}
+
+MUTATOR_HOOKFUNCTION(mayhem, GiveFragsForKill, CBC_ORDER_FIRST)
+{
+       entity frag_attacker = M_ARGV(0, entity);
+       M_ARGV(2, float) = 0; //score to give for the frag directly
+       
+       if (IS_PLAYER(frag_attacker)) FFAMayhemCalculatePlayerScore(frag_attacker);
+       
+       return true;
+}
diff --git a/qcsrc/common/gamemodes/gamemode/mayhem/sv_mayhem.qh b/qcsrc/common/gamemodes/gamemode/mayhem/sv_mayhem.qh
new file mode 100644 (file)
index 0000000..69b2878
--- /dev/null
@@ -0,0 +1,15 @@
+#pragma once
+
+#include <common/mutators/base.qh>
+
+void mayhem_Initialize();
+
+REGISTER_MUTATOR(mayhem, false)
+{
+    MUTATOR_STATIC();
+       MUTATOR_ONADD
+       {
+               mayhem_Initialize();
+       }
+       return 0;
+}
diff --git a/qcsrc/common/gamemodes/gamemode/tmayhem/_mod.inc b/qcsrc/common/gamemodes/gamemode/tmayhem/_mod.inc
new file mode 100644 (file)
index 0000000..e78eb59
--- /dev/null
@@ -0,0 +1,5 @@
+// generated file; do not modify
+#include <common/gamemodes/gamemode/tmayhem/tmayhem.qc>
+#ifdef SVQC
+    #include <common/gamemodes/gamemode/tmayhem/sv_tmayhem.qc>
+#endif
diff --git a/qcsrc/common/gamemodes/gamemode/tmayhem/_mod.qh b/qcsrc/common/gamemodes/gamemode/tmayhem/_mod.qh
new file mode 100644 (file)
index 0000000..2613923
--- /dev/null
@@ -0,0 +1,5 @@
+// generated file; do not modify
+#include <common/gamemodes/gamemode/tmayhem/tmayhem.qh>
+#ifdef SVQC
+    #include <common/gamemodes/gamemode/tmayhem/sv_tmayhem.qh>
+#endif
diff --git a/qcsrc/common/gamemodes/gamemode/tmayhem/sv_tmayhem.qc b/qcsrc/common/gamemodes/gamemode/tmayhem/sv_tmayhem.qc
new file mode 100644 (file)
index 0000000..4c9e7f8
--- /dev/null
@@ -0,0 +1,347 @@
+#include "sv_tmayhem.qh"
+
+float autocvar_g_tmayhem_fraglimit;
+float autocvar_g_tmayhem_visual_score_limit;
+float autocvar_g_tmayhem_score_leadlimit;
+bool autocvar_g_tmayhem_team_spawns;
+float tmayhempointmultiplier;
+
+// TODO? rename to teammayhem? requires checking alias and other string lengths
+int autocvar_g_tmayhem_teams;
+int autocvar_g_tmayhem_teams_override;
+
+bool autocvar_g_tmayhem_regenerate;
+string autocvar_g_tmayhem_weaponarena;
+bool autocvar_g_tmayhem_powerups;
+bool autocvar_g_tmayhem_selfdamage;
+int autocvar_g_tmayhem_scoringmethod;
+float autocvar_g_tmayhem_scoringmethod_1_damage_weight;
+float autocvar_g_tmayhem_scoringmethod_1_frag_weight;
+bool autocvar_g_tmayhem_scoringmethod_1_disable_selfdamage2score;
+bool autocvar_g_tmayhem_pickup_items;
+bool autocvar_g_tmayhem_pickup_items_remove_weapons_and_ammo;
+bool autocvar_g_tmayhem_unlimited_ammo;
+
+float autocvar_g_tmayhem_start_health = 200;
+float autocvar_g_tmayhem_start_armor = 200;
+float autocvar_g_tmayhem_start_ammo_shells = 60;
+float autocvar_g_tmayhem_start_ammo_nails = 320;
+float autocvar_g_tmayhem_start_ammo_rockets = 160;
+float autocvar_g_tmayhem_start_ammo_cells = 180;
+float autocvar_g_tmayhem_start_ammo_plasma = 180;
+float autocvar_g_tmayhem_start_ammo_fuel = 0;
+
+.float total_damage_dealt;
+
+// code from here on is just to support maps that don't have team entities
+void tmayhem_SpawnTeam (string teamname, int teamcolor)
+{
+       entity this = new_pure(tmayhem_team);
+       this.netname = teamname;
+       this.cnt = teamcolor - 1;
+       this.team = teamcolor;
+       this.spawnfunc_checked = true;
+       //spawnfunc_tmayhem_team(this);
+}
+
+void tmayhem_DelayedInit(entity this)
+{
+       // if no teams are found, spawn defaults
+       if(find(NULL, classname, "tmayhem_team") == NULL)
+       {
+               LOG_TRACE("No \"tmayhem_team\" entities found on this map, creating them anyway.");
+
+               int numteams = autocvar_g_tmayhem_teams_override;
+               if(numteams < 2) { numteams = autocvar_g_tmayhem_teams; }
+
+               int teams = BITS(bound(2, numteams, 4));
+               if(teams & BIT(0))
+                       tmayhem_SpawnTeam("Red", NUM_TEAM_1);
+               if(teams & BIT(1))
+                       tmayhem_SpawnTeam("Blue", NUM_TEAM_2);
+               if(teams & BIT(2))
+                       tmayhem_SpawnTeam("Yellow", NUM_TEAM_3);
+               if(teams & BIT(3))
+                       tmayhem_SpawnTeam("Pink", NUM_TEAM_4);
+       }
+}
+
+void tmayhem_Initialize()
+{
+       if(autocvar_g_tmayhem_visual_score_limit != 0 && autocvar_g_tmayhem_fraglimit != 0)
+               tmayhempointmultiplier = autocvar_g_tmayhem_visual_score_limit / autocvar_g_tmayhem_fraglimit;
+
+       GameRules_teams(true);
+       GameRules_spawning_teams(autocvar_g_tmayhem_team_spawns);
+       GameRules_limit_score(autocvar_g_tmayhem_visual_score_limit);
+       GameRules_limit_lead(autocvar_g_tmayhem_score_leadlimit);
+
+       InitializeEntity(NULL, tmayhem_DelayedInit, INITPRIO_GAMETYPE);
+}
+// code up to here is just to support maps that don't have team entities
+
+MUTATOR_HOOKFUNCTION(tmayhem, TeamBalance_CheckAllowedTeams, CBC_ORDER_EXCLUSIVE)
+{
+       M_ARGV(1, string) = "tmayhem_team";
+}
+
+MUTATOR_HOOKFUNCTION(tmayhem, Scores_CountFragsRemaining)
+{
+       // announce remaining frags
+       return true;
+}
+
+MUTATOR_HOOKFUNCTION(tmayhem, SetStartItems)
+{
+       start_items       &= ~(IT_UNLIMITED_AMMO | IT_UNLIMITED_SUPERWEAPONS);
+       if(!cvar("g_use_ammunition") || autocvar_g_tmayhem_unlimited_ammo)
+               start_items |= IT_UNLIMITED_AMMO;
+
+       start_health       = warmup_start_health       = autocvar_g_tmayhem_start_health;
+       start_armorvalue   = warmup_start_armorvalue   = autocvar_g_tmayhem_start_armor;
+       start_ammo_shells  = warmup_start_ammo_shells  = autocvar_g_tmayhem_start_ammo_shells;
+       start_ammo_nails   = warmup_start_ammo_nails   = autocvar_g_tmayhem_start_ammo_nails;
+       start_ammo_rockets = warmup_start_ammo_rockets = autocvar_g_tmayhem_start_ammo_rockets;
+       start_ammo_cells   = warmup_start_ammo_cells   = autocvar_g_tmayhem_start_ammo_cells;
+       start_ammo_plasma  = warmup_start_ammo_plasma  = autocvar_g_tmayhem_start_ammo_plasma;
+       start_ammo_fuel    = warmup_start_ammo_fuel    = autocvar_g_tmayhem_start_ammo_fuel;
+}
+
+//this hook also enables rotting, as players spawn with more hp and armor than what default rot limits are set to this is a bad idea as of now until PlayerRegen is changed
+MUTATOR_HOOKFUNCTION(tmayhem, PlayerRegen)
+{
+       if(autocvar_g_tmayhem_regenerate)
+               return false;
+       return true;
+}
+
+MUTATOR_HOOKFUNCTION(tmayhem, ForbidThrowCurrentWeapon)
+{
+       return true;
+}
+
+MUTATOR_HOOKFUNCTION(tmayhem, SetWeaponArena)
+{
+       if (M_ARGV(0, string) == "0" || M_ARGV(0, string) == "")
+               M_ARGV(0, string) = autocvar_g_tmayhem_weaponarena;
+}
+
+MUTATOR_HOOKFUNCTION(tmayhem, FilterItem)
+{
+       entity item = M_ARGV(0, entity);
+       
+       //enable powerups if forced globally or global accepts gamemodes to have powerups according to their own settings
+       if (autocvar_g_powerups == 1 || (autocvar_g_powerups == -1 && autocvar_g_tmayhem_powerups == 1)){
+               if (item.itemdef.instanceOfPowerup){
+                       return false;
+               } 
+       }
+       //disabled powerups if forced off globally or in this gamemode
+       if (autocvar_g_powerups == 0 || autocvar_g_tmayhem_powerups == 0){
+               if (item.itemdef.instanceOfPowerup){
+                       return true; 
+               } 
+       }
+       //remove all items if items are forced off globally
+       if (autocvar_g_pickup_items == 0){
+               return true;
+       }
+       //if items are switched on in this gamemode allow the removal of weapons and ammo still
+       if ((autocvar_g_tmayhem_pickup_items == 1 && autocvar_g_tmayhem_pickup_items_remove_weapons_and_ammo == 1) && autocvar_g_pickup_items <= 0){
+               if (item.itemdef.instanceOfAmmo || item.itemdef.instanceOfWeaponPickup){
+                       return true;
+               }
+       }
+       //remove items if not globally set to follow mode's settings and locally set off
+       if (autocvar_g_pickup_items == -1 && autocvar_g_tmayhem_pickup_items == 0){
+               return true;
+       }
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(tmayhem, Damage_Calculate)
+{
+       entity frag_attacker = M_ARGV(1, entity);
+       entity frag_target = M_ARGV(2, entity);
+       float frag_deathtype = M_ARGV(3, float);
+       float frag_damage = M_ARGV(4, float);
+       float frag_mirrordamage = M_ARGV(5, float);
+
+       if (IS_PLAYER(frag_target)) //don't ever zero damage to non-players
+       if (!IS_DEAD(frag_target)) //enable anyone to gib corpses
+       if ((autocvar_g_tmayhem_selfdamage == 0 && frag_target == frag_attacker) || frag_deathtype == DEATH_FALL.m_id) //nullify self-damage if self-damage is disabled and always nullify splat
+               frag_damage = 0;
+
+       frag_mirrordamage = 0; //no mirror damaging
+
+       M_ARGV(4, float) = frag_damage;
+       M_ARGV(5, float) = frag_mirrordamage;
+}
+
+void TeamMayhemCalculatePlayerScore(entity scorer){
+       switch (autocvar_g_tmayhem_scoringmethod)
+       {
+               default:
+               case 1:
+               {
+                       //calculate how much score the player should have based on their damage dealt and frags gotten and then add the missing score
+
+                       //give a different weight for suicides if scoring method 1 doesn't have selfdamage2score enabled to harshly punish for suicides to avoid exploiting
+                       float suicide_weight = 1 + (autocvar_g_tmayhem_scoringmethod_1_disable_selfdamage2score * (1/autocvar_g_tmayhem_scoringmethod_1_frag_weight));
+
+                       //total damage divided by player start health&armor to get how many lives worth of damage they've dealt, then how much that is out of the fraglimit, then calculate new value affected by weight
+                       float playerdamagescore = (((((scorer.total_damage_dealt/(start_health + start_armorvalue)) * 100)/autocvar_g_tmayhem_fraglimit) * autocvar_g_tmayhem_scoringmethod_1_damage_weight) );
+                                                                                                                                                                                                       //  * 100 to avoid float inaccuracy at that decimal level
+
+                       //playerdamagescore rounded
+                       float roundedplayerdamagescore = ((rint(playerdamagescore*10))/10);
+
+                       //kills minus suicides, total out of fraglimit, calculate weight
+                       float playerkillscore = ((((PlayerScore_Get(scorer, SP_KILLS) - (PlayerScore_Get(scorer, SP_SUICIDES) * suicide_weight)) * 100) / autocvar_g_tmayhem_fraglimit) * autocvar_g_tmayhem_scoringmethod_1_frag_weight);
+                                                                                                                                                                                                                                                               //   * 100 to avoid float inaccuracy at that decimal level
+
+                       //only used for debug print, add killscore and damagescore together
+                       float playerscore = (roundedplayerdamagescore + playerkillscore);
+
+                       //add killscore and damagescore together to get total score and then adjust it to be total out of the visual score limit
+                       float playerscorevisual = ((roundedplayerdamagescore + playerkillscore) * autocvar_g_tmayhem_visual_score_limit);
+                                                                                                                                                                                                                                               
+
+                       //calculated how much score the player has and now calculate total of how much they are supposed to have
+                       float scoretoadd = (playerscorevisual - (PlayerScore_Get(scorer, SP_SCORE) * 100));
+                                                                                                                                                                  //  * 100 to avoid float inaccuracy at that decimal level
+
+                       //adjust total score to be what the player is supposed to have
+                       GameRules_scoring_add_team(scorer, SCORE, floor(scoretoadd / 100));
+                                                                                                                                       // / 100 to move back to the decimal level
+
+                       if(0){
+                               //debug printing
+                               if(!IS_BOT_CLIENT(scorer)){
+                                       print(sprintf("%f", scorer.total_damage_dealt),                 " scorer.total_damage_dealt \n");
+                                       print(sprintf("%f", playerdamagescore),                                 " playerdamagescore \n");
+                                       print(sprintf("%f", roundedplayerdamagescore),                  " rounded playerdamagescore \n");
+                                       print(sprintf("%f", playerkillscore),                                   " playerkillscore \n");
+                                       print(sprintf("%f", PlayerScore_Get(scorer, SP_KILLS)), " PlayerScore_Get(scorer, SP_KILLS) \n");
+                                       print(sprintf("%f", playerscore),                                               " playerscore \n");
+                                       print(sprintf("%f", playerscorevisual),                                 " visual playerscore \n");
+                                       print(sprintf("%f", scoretoadd),                                                " scoretoadd \n");
+                                       print(sprintf("%f", PlayerScore_Get(scorer, SP_SCORE)), " PlayerScore_Get(scorer, SP_SCORE) \n \n");
+                               }
+                       }
+               return;
+               }
+
+               case 2:
+               {
+                       //calculate how much score the player should have based on their frags gotten and then add the missing score
+                       float playerkillscore = (((PlayerScore_Get(scorer, SP_KILLS) - PlayerScore_Get(scorer, SP_SUICIDES)) * 100)/ autocvar_g_tmayhem_fraglimit);
+                       float playerscorevisual = (playerkillscore * autocvar_g_tmayhem_visual_score_limit) / 100;
+                       float scoretoadd = (playerscorevisual - PlayerScore_Get(scorer, SP_SCORE));
+                       GameRules_scoring_add_team(scorer, SCORE, floor(scoretoadd));
+
+                       if(0){
+                               //debug printing
+                               if(!IS_BOT_CLIENT(scorer)){
+                                       print(sprintf("%f", playerkillscore),                                   " playerkillscore \n");
+                                       print(sprintf("%f", PlayerScore_Get(scorer, SP_KILLS)), " PlayerScore_Get(scorer, SP_KILLS) \n");
+                                       print(sprintf("%f", playerscorevisual),                                 " visual playerscore \n");
+                                       print(sprintf("%f", scoretoadd),                                                " scoretoadd \n");
+                                       print(sprintf("%f", PlayerScore_Get(scorer, SP_SCORE)), " PlayerScore_Get(scorer, SP_SCORE) \n \n");
+                               }
+                       }
+               return;
+               }
+
+               case 3:
+               {
+                       //calculate how much score the player should have based on their damage dealt and then add the missing score
+                       float playerdamagescore = (((scorer.total_damage_dealt/(start_health + start_armorvalue)) * 100)/autocvar_g_tmayhem_fraglimit);
+                       float roundedplayerdamagescore = ((rint(playerdamagescore*10))/10);
+                       float playerscorevisual = (roundedplayerdamagescore * autocvar_g_tmayhem_visual_score_limit);
+                       float scoretoadd = (playerscorevisual - (PlayerScore_Get(scorer, SP_SCORE) * 100));
+                       GameRules_scoring_add_team(scorer, SCORE, floor(scoretoadd / 100));
+
+                       if(0){
+                               //debug printing
+                               if(!IS_BOT_CLIENT(scorer)){
+                                       print(sprintf("%f", scorer.total_damage_dealt),                 " scorer.total_damage_dealt \n");
+                                       print(sprintf("%f", playerdamagescore),                                 " playerdamagescore \n");
+                                       print(sprintf("%f", roundedplayerdamagescore),                  " rounded playerdamagescore \n");
+                                       print(sprintf("%f", playerscorevisual),                                 " visual playerscore \n");
+                                       print(sprintf("%f", scoretoadd),                                                " scoretoadd \n");
+                                       print(sprintf("%f", PlayerScore_Get(scorer, SP_SCORE)), " PlayerScore_Get(scorer, SP_SCORE) \n \n");
+                               }
+                       }
+               return;
+               }
+       }
+}
+
+MUTATOR_HOOKFUNCTION(tmayhem, PlayerDamage_SplitHealthArmor)
+{
+       if (autocvar_g_tmayhem_scoringmethod==2) return;
+       
+       entity frag_target = M_ARGV(2, entity);
+
+       if (StatusEffects_active(STATUSEFFECT_SpawnShield, frag_target) && autocvar_g_spawnshield_blockdamage >= 1)return;
+       
+       entity frag_attacker = M_ARGV(1, entity);
+       float frag_deathtype = M_ARGV(6, float);
+       float frag_damage = M_ARGV(7, float);
+       float damage_take = bound(0, M_ARGV(4, float), GetResource(frag_target, RES_HEALTH));
+       float damage_save = bound(0, M_ARGV(5, float), GetResource(frag_target, RES_ARMOR));
+       float excess = max(0, frag_damage - damage_take - damage_save);
+       float total = frag_damage - excess;
+
+       if (total == 0) return;
+
+       if (StatusEffects_active(STATUSEFFECT_SpawnShield, frag_target) && autocvar_g_spawnshield_blockdamage < 1)
+               total *= 1 - bound(0, autocvar_g_spawnshield_blockdamage, 1);
+
+       entity scorer = NULL; //entity which needs their score to be updated
+
+       if (IS_PLAYER(frag_attacker))
+       {
+               //non-friendly fire
+               if (!SAME_TEAM(frag_target, frag_attacker))
+                       frag_attacker.total_damage_dealt += total;
+
+               //friendly fire aka self damage
+               if (SAME_TEAM(frag_target, frag_attacker) || (frag_target == frag_attacker && !autocvar_g_tmayhem_scoringmethod_1_disable_selfdamage2score))
+                       frag_attacker.total_damage_dealt -= total;
+
+               scorer = frag_attacker;
+       }
+       else
+       {
+               //handle (environmental hazard) suiciding, check first if player has a registered attacker who most likely pushed them there to avoid punishing pushed players as pushers are already rewarded
+               //deathtypes:
+               //kill = suicide, drown = drown in water/liquid, hurttrigger = out of the map void or hurt triggers inside maps like electric sparks
+               //camp = campcheck, lava = lava, slime = slime
+               //team change / rebalance suicides are currently not included
+               if (!autocvar_g_tmayhem_scoringmethod_1_disable_selfdamage2score && (
+                       frag_deathtype == DEATH_KILL.m_id ||
+                       frag_deathtype == DEATH_DROWN.m_id ||
+                       frag_deathtype == DEATH_HURTTRIGGER.m_id ||
+                       frag_deathtype == DEATH_CAMP.m_id ||
+                       frag_deathtype == DEATH_LAVA.m_id ||
+                       frag_deathtype == DEATH_SLIME.m_id ||
+                       frag_deathtype == DEATH_SWAMP.m_id))
+                               frag_target.total_damage_dealt -= total;
+
+               scorer = frag_target;
+       }
+
+       TeamMayhemCalculatePlayerScore(scorer);
+}
+
+MUTATOR_HOOKFUNCTION(tmayhem, GiveFragsForKill, CBC_ORDER_FIRST)
+{
+       entity frag_attacker = M_ARGV(0, entity);
+       M_ARGV(2, float) = 0; //score to give for the frag directly
+       
+       if (IS_PLAYER(frag_attacker)) TeamMayhemCalculatePlayerScore(frag_attacker);
+       
+       return true;
+}
diff --git a/qcsrc/common/gamemodes/gamemode/tmayhem/sv_tmayhem.qh b/qcsrc/common/gamemodes/gamemode/tmayhem/sv_tmayhem.qh
new file mode 100644 (file)
index 0000000..c31967f
--- /dev/null
@@ -0,0 +1,15 @@
+#pragma once
+
+#include <common/mutators/base.qh>
+
+void tmayhem_Initialize();
+
+REGISTER_MUTATOR(tmayhem, false)
+{
+    MUTATOR_STATIC();
+       MUTATOR_ONADD
+       {
+               tmayhem_Initialize();
+       }
+       return 0;
+}
diff --git a/qcsrc/common/gamemodes/gamemode/tmayhem/tmayhem.qc b/qcsrc/common/gamemodes/gamemode/tmayhem/tmayhem.qc
new file mode 100644 (file)
index 0000000..b05860a
--- /dev/null
@@ -0,0 +1 @@
+#include "tmayhem.qh"
diff --git a/qcsrc/common/gamemodes/gamemode/tmayhem/tmayhem.qh b/qcsrc/common/gamemodes/gamemode/tmayhem/tmayhem.qh
new file mode 100644 (file)
index 0000000..0e18d05
--- /dev/null
@@ -0,0 +1,51 @@
+#pragma once
+
+#include <common/gamemodes/gamemode/deathmatch/deathmatch.qh>
+#include <common/gamemodes/gamemode/tdm/tdm.qh>
+#include <common/mapinfo.qh>
+
+CLASS(tmayhem, Gametype)
+    INIT(tmayhem)
+    {
+        this.gametype_init(this, _("Team Mayhem"),"tmayhem","g_tmayhem",GAMETYPE_FLAG_TEAMPLAY | GAMETYPE_FLAG_USEPOINTS | GAMETYPE_FLAG_PRIORITY,"","timelimit=15 pointlimit=50 teams=2 leadlimit=0",_("Compete with your team for the most damage dealt and frags in this chaotic mayhem!"));
+    }
+    METHOD(tmayhem, m_parse_mapinfo, bool(string k, string v))
+    {
+        if (!k) {
+            cvar_set("g_tmayhem_teams", cvar_defstring("g_tmayhem_teams"));
+            return true;
+        }
+        switch (k) {
+            case "teams":
+                cvar_set("g_tmayhem_teams", v);
+                return true;
+        }
+        return false;
+    }
+    METHOD(tmayhem, m_isAlwaysSupported, bool(Gametype this, int spawnpoints, float diameter))
+    {
+        return true;
+    }
+    METHOD(tmayhem, m_isForcedSupported, bool(Gametype this))
+    {
+        if(!(MapInfo_Map_supportedGametypes & this.m_flags) && (MapInfo_Map_supportedGametypes & MAPINFO_TYPE_DEATHMATCH.m_flags)){
+               return true;
+        }
+        if(!(MapInfo_Map_supportedGametypes & this.m_flags) && (MapInfo_Map_supportedGametypes & MAPINFO_TYPE_TEAM_DEATHMATCH.m_flags)){
+               return true;
+        }
+        return false;          
+    }
+    METHOD(tmayhem, m_setTeams, void(string sa))
+    {
+        cvar_set("g_tmayhem_teams", sa);
+    }
+    METHOD(tmayhem, m_configuremenu, void(Gametype this, entity menu, void(entity me, string pLabel, float pMin, float pMax, float pStep, string pCvar, string tCvar, string pTooltip) returns))
+    {
+        TC(Gametype, this);
+        returns(menu, _("Frag limit:"),     5,  100,  5, "g_tmayhem_fraglimit",         "g_tmayhem_teams_override",         _("How many frags worth of score is needed before the match will end"));
+    }
+    ATTRIB(tmayhem, m_legacydefaults, string, "50 20 2 0");
+ENDCLASS(tmayhem)
+REGISTER_GAMETYPE(TEAM_MAYHEM, NEW(tmayhem));
+#define g_tmayhem IS_GAMETYPE(TEAM_MAYHEM)
index e77049d200153e9c2f15fb0ca097edd1c1649fe3..90bc3a1bd7520687c9dcb8ff2d7cb2358e42603b 100644 (file)
@@ -674,6 +674,8 @@ float updateCompression()
        GAMETYPE(MAPINFO_TYPE_CTF) \
        GAMETYPE(MAPINFO_TYPE_CA) \
        GAMETYPE(MAPINFO_TYPE_FREEZETAG) \
+       GAMETYPE(MAPINFO_TYPE_TEAM_MAYHEM) \
+       GAMETYPE(MAPINFO_TYPE_MAYHEM) \
        GAMETYPE(MAPINFO_TYPE_KEEPAWAY) \
        GAMETYPE(MAPINFO_TYPE_KEYHUNT) \
        GAMETYPE(MAPINFO_TYPE_LMS) \
index e2a44d2c8b71e29d28a02138543ea4faf0f3f44a..80583f1571b2fd3759ad1653801e7f6bb9e0f7c4 100644 (file)
@@ -287,6 +287,7 @@ void cvar_changes_init()
                BADCVAR("g_keyhunt");
                BADCVAR("g_keyhunt_teams");
                BADCVAR("g_lms");
+               BADCVAR("g_mayhem");
                BADCVAR("g_nexball");
                BADCVAR("g_onslaught");
                BADCVAR("g_race");
@@ -301,6 +302,8 @@ void cvar_changes_init()
                BADCVAR("g_tdm");
                BADCVAR("g_tdm_on_dm_maps");
                BADCVAR("g_tdm_teams");
+               BADCVAR("g_tmayhem");
+               BADCVAR("g_tmayhem_teams");
                BADCVAR("g_vip");
                BADCVAR("leadlimit");
                BADCVAR("nextmap");
@@ -377,8 +380,19 @@ void cvar_changes_init()
                BADCVAR("g_spawn_alloweffects");
                BADCVAR("g_tdm_point_leadlimit");
                BADCVAR("g_tdm_point_limit");
+               BADCVAR("g_mayhem_fraglimit");
+               BADCVAR("g_tmayhem_fraglimit");
+               BADCVAR("g_mayhem_visual_score_limit");
+               BADCVAR("g_tmayhem_visual_score_limit");
+               BADCVAR("g_tmayhem_score_leadlimit");
                BADCVAR("leadlimit_and_fraglimit");
                BADCVAR("leadlimit_override");
+               BADCVAR("g_mayhem_scoringmethod");
+               BADCVAR("g_mayhem_scoringmethod_damage_weight");
+               BADCVAR("g_mayhem_scoringmethod_frag_weight");
+               BADCVAR("g_tmayhem_scoringmethod");
+               BADCVAR("g_tmayhem_scoringmethod_damage_weight");
+               BADCVAR("g_tmayhem_scoringmethod_frag_weight");
                BADCVAR("pausable");
                BADCVAR("sv_announcer");
                BADCVAR("sv_checkforpacketsduringsleep");
@@ -453,6 +467,7 @@ void cvar_changes_init()
                BADCVAR("g_keyhunt_point_limit");
                BADCVAR("g_keyhunt_teams_override");
                BADCVAR("g_lms_lives_override");
+               BADCVAR("g_mayhem_powerups");
                BADCVAR("g_maplist");
                BADCVAR("g_maxplayers");
                BADCVAR("g_mirrordamage");
@@ -469,6 +484,8 @@ void cvar_changes_init()
                BADCVAR("g_start_delay");
                BADCVAR("g_superspectate");
                BADCVAR("g_tdm_teams_override");
+               BADCVAR("g_tmayhem_teams_override");
+               BADCVAR("g_tmayhem_powerups");
                BADCVAR("g_warmup");
                BADCVAR("g_weapon_stay"); BADPRESUFFIX("g_", "_weapon_stay");
                BADCVAR("hostname");
@@ -524,6 +541,8 @@ void cvar_changes_init()
                BADCVAR("g_ca_weaponarena");
                BADCVAR("g_freezetag_weaponarena");
                BADCVAR("g_lms_weaponarena");
+               BADCVAR("g_mayhem_weaponarena");
+               BADCVAR("g_tmayhem_weaponarena");
                BADCVAR("g_ctf_stalemate_time");
 
 #undef BADPRESUFFIX