Each player spawns with 200/200 and full ammo like in LMS&CA and pickup items are removed by default, powerups are kept for extra spice but can be removed with whitelisted cvars.
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
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
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
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
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
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
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
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
alias cl_hook_shutdown
alias cl_hook_activeweapon
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
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.
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
// =========
//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 kills in this chaotic mayhem!"
+set g_tmayhem 0 "Team Mayhem: Compete with your team for the most damage dealt and kills in this chaotic mayhem!"
+
+set g_mayhem_scoring_upscaler 20 "upscale one frag's worth to be this amount of in score"
+set g_tmayhem_scoring_upscaler 20 "upscale one frag's worth to be this amount of in score"
+set g_mayhem_scoring_kill_weight 0.25 "how much is a kill worth in frags"
+set g_tmayhem_scoring_kill_weight 0.25 "how much is a kill worth in frags"
+set g_mayhem_scoring_damage_weight 0.75 "how much is damage equal to player's spawning health+armor worth in frags"
+set g_tmayhem_scoring_damage_weight 0.75 "how much is damage equal to player's spawning health+armor worth in frags"
+set g_mayhem_scoring_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_scoring_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_point_limit -1 "Mayhem score limit overriding the mapinfo specified one (use 0 to play without limit, and -1 to use the mapinfo's limit)"
+set g_mayhem_point_leadlimit -1 "Mayhem score lead limit overriding the mapinfo specified one (use 0 to play without limit, and -1 to use the mapinfo's limit)"
+set g_tmayhem_point_limit -1 "Team Mayhem score limit overriding the mapinfo specified one (use 0 to play without limit, and -1 to use the mapinfo's limit)"
+set g_tmayhem_point_leadlimit -1 "Team Mayhem score lead limit 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 "health and/or armor regeneration, according to g_balance_health_regen and g_balance_armor_regen"
+set g_tmayhem_regenerate 0 "health and/or armor regeneration, according to g_balance_health_regen and g_balance_armor_regen"
+set g_mayhem_rot 0 "health and/or armor rotting, according to g_balance_health_rot and g_balance_armor_rot"
+set g_tmayhem_rot 0 "health and/or armor rotting, according to g_balance_health_rot and g_balance_armor_rot"
+
+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"
#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
#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
--- /dev/null
+// generated file; do not modify
+#include <common/gamemodes/gamemode/mayhem/mayhem.qc>
+#ifdef SVQC
+ #include <common/gamemodes/gamemode/mayhem/sv_mayhem.qc>
+#endif
--- /dev/null
+// generated file; do not modify
+#include <common/gamemodes/gamemode/mayhem/mayhem.qh>
+#ifdef SVQC
+ #include <common/gamemodes/gamemode/mayhem/sv_mayhem.qh>
+#endif
--- /dev/null
+#include "mayhem.qh"
--- /dev/null
+#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,"","timelimit=15 pointlimit=1000 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, _("Point limit:"), 200, 2000, 100, "g_mayhem_point_limit", string_null, _("How much score is needed before the match will end"));
+ }
+ ATTRIB(mayhem, m_legacydefaults, string, "1000 20 0");
+ENDCLASS(mayhem)
+REGISTER_GAMETYPE(MAYHEM, NEW(mayhem));
--- /dev/null
+#include "sv_mayhem.qh"
+#include <common/scores.qh>
+
+// import autocvars for MayhemCalculatePlayerScore's teamplay cvars
+#include "common/gamemodes/gamemode/tmayhem/sv_tmayhem.qh"
+
+float autocvar_g_mayhem_point_limit;
+float autocvar_g_mayhem_point_leadlimit;
+
+bool autocvar_g_mayhem_regenerate;
+bool autocvar_g_mayhem_rot;
+string autocvar_g_mayhem_weaponarena;
+bool autocvar_g_mayhem_powerups;
+bool autocvar_g_mayhem_selfdamage;
+float autocvar_g_mayhem_scoring_upscaler;
+float autocvar_g_mayhem_scoring_damage_weight;
+float autocvar_g_mayhem_scoring_kill_weight;
+bool autocvar_g_mayhem_scoring_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;
+
+/*
+// unused for now
+void mayhem_DelayedInit(entity this)
+{
+ return;
+}
+*/
+
+void mayhem_Initialize()
+{
+ GameRules_limit_score(autocvar_g_mayhem_point_limit);
+ GameRules_limit_lead(autocvar_g_mayhem_point_leadlimit);
+
+ // unused for now
+ //InitializeEntity(NULL, mayhem_DelayedInit, INITPRIO_GAMETYPE);
+}
+
+/*
+MUTATOR_HOOKFUNCTION(mayhem, Scores_CountFragsRemaining)
+{
+ // do not announce remaining frags, upscaled score count doesn't match well with this
+ // when scorelimit is set to 1000 it would announce 997, 998 and 999 score counts
+ // usually a single shot which deals ~40-80 dmg gives 2 or 3 score
+ // this usually would cause a "2 fra..." announcement to be played as the match ends
+ // without leaving anyone time to even process the announcement
+ return false;
+}
+*/
+
+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;
+}
+
+MUTATOR_HOOKFUNCTION(mayhem, PlayerRegen)
+{
+ if(!autocvar_g_mayhem_regenerate)
+ M_ARGV(2, float) = 0;
+ if(!autocvar_g_mayhem_rot)
+ M_ARGV(3, float) = 0;
+ return (!autocvar_g_mayhem_regenerate && !autocvar_g_mayhem_rot);
+}
+
+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 (IS_PLAYER(frag_target)) // nullify self-damage if self-damage is disabled and always nullify splat
+ if (!IS_DEAD(frag_target)) // but enable anyone to gib corpses, even their own corpses with delayed damage
+ 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 MayhemCalculatePlayerScore(entity scorer)
+{
+ int scoringmethod = 1;
+ float upscaler; // how much score does 1 frag give
+ float frag_weight; // how many frags should a kill be worth
+ float damage_weight; // how many frags is damage worth of player's spawn health+armor
+
+ // if frag is 0.25 , damage is 0.75 and upscaler is 20
+ // then killing a full hp opponent is 1 frag which is worth of 20 score
+ // or damage worth of 2 starting health+armor is 1.5 frags or 30 score even if no kills were gotten
+
+ bool disable_selfdamage2score;
+
+ if (teamplay) {
+ // use Team Mayhem values
+ upscaler = autocvar_g_tmayhem_scoring_upscaler;
+ frag_weight = autocvar_g_tmayhem_scoring_kill_weight;
+ damage_weight = autocvar_g_tmayhem_scoring_damage_weight;
+ disable_selfdamage2score = autocvar_g_tmayhem_scoring_disable_selfdamage2score;
+ } else {
+ // use FFA Mayhem values
+ upscaler = autocvar_g_mayhem_scoring_upscaler;
+ frag_weight = autocvar_g_mayhem_scoring_kill_weight;
+ damage_weight = autocvar_g_mayhem_scoring_damage_weight;
+ disable_selfdamage2score = autocvar_g_mayhem_scoring_disable_selfdamage2score;
+ }
+
+ // decide scoringmethod and avoid potential divide by 0 errors
+
+ if (frag_weight && damage_weight) // both frag and damage weights have non-zero values
+ scoringmethod = 1;
+ else if (frag_weight) // frag weight has a value
+ scoringmethod = 2;
+ else if (damage_weight) // damage weight has a value
+ scoringmethod = 3;
+ else
+ return; // neither frags nor damage are set to give score
+
+ switch (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 + (disable_selfdamage2score / frag_weight);
+
+ // total damage divided by player start health&armor to get how many lives worth of damage they've dealt,
+ // then calculate new value affected by weight
+ float playerdamagescore = ((scorer.total_damage_dealt / (start_health + start_armorvalue)) * 100) * upscaler * damage_weight;
+ // * 100 to avoid float inaccuracy at that decimal level
+
+ // playerdamagescore rounded to one decimal
+ float roundedplayerdamagescore = rint(playerdamagescore * 10) / 10;
+
+ // amount of kills
+ float killcount = PlayerScore_Get(scorer, SP_KILLS) - PlayerScore_Get(scorer, SP_TEAMKILLS) - (PlayerScore_Get(scorer, SP_SUICIDES) * suicide_weight);
+
+ // kills minus suicides, calculate weight
+ float playerkillscore = (killcount * 100) * upscaler * frag_weight;
+ // * 100 to avoid float inaccuracy at that decimal level
+
+ float playerscore = roundedplayerdamagescore + playerkillscore;
+
+ // calculated how much score the player has and now calculate total of how much they are supposed to have
+ float scoretoadd = playerscore - (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 original 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", scorer.hitsound_damage_dealt), " scorer.hitsound_damage_dealt \n");
+ print(sprintf("%f", playerdamagescore/100), " playerdamagescore \n");
+ print(sprintf("%f", roundedplayerdamagescore/100), " rounded playerdamagescore \n");
+ print(sprintf("%f", playerkillscore/100), " playerkillscore \n");
+ print(sprintf("%f", PlayerScore_Get(scorer, SP_KILLS)), " PlayerScore_Get(scorer, SP_KILLS) \n");
+ print(sprintf("%f", playerscore/100), " playerscore \n");
+ print(sprintf("%f", scoretoadd/100), " scoretoadd \n");
+ print(sprintf("%f", PlayerScore_Get(scorer, SP_SCORE)), " PlayerScore_Get(scorer, SP_SCORE) \n \n");
+ }
+ #endif
+ 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_TEAMKILLS) - PlayerScore_Get(scorer, SP_SUICIDES);
+ float upscaledplayerscore = playerkillscore * upscaler;
+ float scoretoadd = upscaledplayerscore - 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", upscaledplayerscore), " upscaled playerscore \n");
+ print(sprintf("%f", scoretoadd), " scoretoadd \n");
+ print(sprintf("%f", PlayerScore_Get(scorer, SP_SCORE)), " PlayerScore_Get(scorer, SP_SCORE) \n \n");
+ }
+ #endif
+ 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);
+ float roundedplayerdamagescore = rint(playerdamagescore * 10) / 10;
+ float upscaledplayerscore = roundedplayerdamagescore * upscaler;
+ float scoretoadd = upscaledplayerscore - (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", upscaledplayerscore), " upscaled playerscore \n");
+ print(sprintf("%f", scoretoadd), " scoretoadd \n");
+ print(sprintf("%f", PlayerScore_Get(scorer, SP_SCORE)), " PlayerScore_Get(scorer, SP_SCORE) \n \n");
+ }
+ #endif
+ return;
+ }
+ }
+}
+
+MUTATOR_HOOKFUNCTION(mayhem, PlayerDamage_SplitHealthArmor)
+{
+ if (!autocvar_g_mayhem_scoring_damage_weight) 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)
+ total *= 1 - autocvar_g_spawnshield_blockdamage;
+
+ 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_scoring_disable_selfdamage2score)
+ frag_attacker.total_damage_dealt -= total;
+
+ scorer = frag_attacker;
+ }
+ else
+ {
+ // handle (environmental hazard) suiciding, check first if the 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_scoring_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;
+ }
+
+ #if 0
+ // debug printing
+ if(!IS_BOT_CLIENT(scorer)){
+ print(sprintf("%f", total), " total dmg from PlayerDamage_SplitHealthArmor \n");
+ print(sprintf("%f", scorer.total_damage_dealt), "scorer.total_damage_dealt\n");
+ }
+ #endif
+
+ MayhemCalculatePlayerScore(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)) MayhemCalculatePlayerScore(frag_attacker);
+
+ return true;
+}
+
+MUTATOR_HOOKFUNCTION(mayhem, reset_map_players)
+{
+ // reset damage dealt on reset
+ FOREACH_CLIENT(true, {
+ it.total_damage_dealt = 0;
+ });
+ return false;
+}
+
--- /dev/null
+#pragma once
+
+#include <common/mutators/base.qh>
+
+void mayhem_Initialize();
+
+REGISTER_MUTATOR(mayhem, false)
+{
+ MUTATOR_STATIC();
+ MUTATOR_ONADD
+ {
+ mayhem_Initialize();
+ }
+ return 0;
+}
+
+void MayhemCalculatePlayerScore(entity scorer);
--- /dev/null
+// generated file; do not modify
+#include <common/gamemodes/gamemode/tmayhem/tmayhem.qc>
+#ifdef SVQC
+ #include <common/gamemodes/gamemode/tmayhem/sv_tmayhem.qc>
+#endif
--- /dev/null
+// generated file; do not modify
+#include <common/gamemodes/gamemode/tmayhem/tmayhem.qh>
+#ifdef SVQC
+ #include <common/gamemodes/gamemode/tmayhem/sv_tmayhem.qh>
+#endif
--- /dev/null
+#include "sv_tmayhem.qh"
+#include "common/gamemodes/gamemode/mayhem/sv_mayhem.qh"
+
+float autocvar_g_tmayhem_point_limit;
+float autocvar_g_tmayhem_point_leadlimit;
+
+int autocvar_g_tmayhem_teams;
+int autocvar_g_tmayhem_teams_override;
+bool autocvar_g_tmayhem_team_spawns;
+
+bool autocvar_g_tmayhem_regenerate;
+bool autocvar_g_tmayhem_rot;
+string autocvar_g_tmayhem_weaponarena;
+bool autocvar_g_tmayhem_powerups;
+bool autocvar_g_tmayhem_selfdamage;
+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()
+{
+ GameRules_teams(true);
+ GameRules_spawning_teams(autocvar_g_tmayhem_team_spawns);
+
+ GameRules_limit_score(autocvar_g_tmayhem_point_limit);
+ GameRules_limit_lead(autocvar_g_tmayhem_point_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)
+{
+ // do not announce remaining frags, upscaled score count doesn't match well with this
+ // when scorelimit is set to 1000 it would announce 997, 998 and 999 score counts
+ // usually a single shot which deals ~40-80 dmg gives 2 or 3 score
+ // this usually would cause a "2 fra..." announcement to be played as the match ends
+ // without leaving anyone time to even process the announcement
+ return false;
+}
+*/
+
+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;
+}
+
+MUTATOR_HOOKFUNCTION(tmayhem, PlayerRegen)
+{
+ if(!autocvar_g_tmayhem_regenerate)
+ M_ARGV(2, float) = 0;
+ if(!autocvar_g_tmayhem_rot)
+ M_ARGV(3, float) = 0;
+ return (!autocvar_g_tmayhem_regenerate && !autocvar_g_tmayhem_rot);
+}
+
+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)) // nullify self-damage if self-damage is disabled and always nullify splat
+ if (!IS_DEAD(frag_target)) // but enable anyone to gib corpses, even their own corpses with delayed damage
+ if ((autocvar_g_tmayhem_selfdamage == 0 && frag_target == frag_attacker) || frag_deathtype == DEATH_FALL.m_id)
+ frag_damage = 0;
+
+ frag_mirrordamage = 0; // no mirror damaging
+
+ M_ARGV(4, float) = frag_damage;
+ M_ARGV(5, float) = frag_mirrordamage;
+}
+
+MUTATOR_HOOKFUNCTION(tmayhem, PlayerDamage_SplitHealthArmor)
+{
+ if (!autocvar_g_tmayhem_scoring_damage_weight) 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)
+ total *= 1 - autocvar_g_spawnshield_blockdamage;
+
+ 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_scoring_disable_selfdamage2score))
+ frag_attacker.total_damage_dealt -= total;
+
+ scorer = frag_attacker;
+ }
+ else
+ {
+ // handle (environmental hazard) suiciding, check first if the 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_scoring_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;
+ }
+
+ MayhemCalculatePlayerScore(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)) MayhemCalculatePlayerScore(frag_attacker);
+
+ return true;
+}
+
+MUTATOR_HOOKFUNCTION(tmayhem, reset_map_players)
+{
+ // reset damage dealt on reset
+ FOREACH_CLIENT(true, {
+ it.total_damage_dealt = 0;
+ });
+ return false;
+}
+
--- /dev/null
+#pragma once
+
+#include <common/mutators/base.qh>
+
+// autocvars defined here so they can be imported in FFA sv_mayhem.qc
+float autocvar_g_tmayhem_scoring_upscaler;
+float autocvar_g_tmayhem_scoring_kill_weight;
+float autocvar_g_tmayhem_scoring_damage_weight;
+bool autocvar_g_tmayhem_scoring_disable_selfdamage2score;
+
+void tmayhem_Initialize();
+
+REGISTER_MUTATOR(tmayhem, false)
+{
+ MUTATOR_STATIC();
+ MUTATOR_ONADD
+ {
+ tmayhem_Initialize();
+ }
+ return 0;
+}
--- /dev/null
+#include "tmayhem.qh"
--- /dev/null
+#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,"","timelimit=20 pointlimit=1500 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, _("Point limit:"), 200, 3000, 100, "g_tmayhem_point_limit", "g_tmayhem_teams_override", _("How much score is needed before the match will end"));
+ }
+ ATTRIB(tmayhem, m_legacydefaults, string, "1500 20 2 0");
+ENDCLASS(tmayhem)
+REGISTER_GAMETYPE(TEAM_MAYHEM, NEW(tmayhem));
+#define g_tmayhem IS_GAMETYPE(TEAM_MAYHEM)
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) \
BADCVAR("g_keyhunt");
BADCVAR("g_keyhunt_teams");
BADCVAR("g_lms");
+ BADCVAR("g_mayhem");
BADCVAR("g_nexball");
BADCVAR("g_onslaught");
BADCVAR("g_race");
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");
BADCVAR("g_spawn_alloweffects");
BADCVAR("g_tdm_point_leadlimit");
BADCVAR("g_tdm_point_limit");
+ BADCVAR("g_mayhem_point_limit");
+ BADCVAR("g_mayhem_point_leadlimit");
+ BADCVAR("g_tmayhem_point_limit");
+ BADCVAR("g_tmayhem_point_leadlimit");
BADCVAR("leadlimit_and_fraglimit");
BADCVAR("leadlimit_override");
BADCVAR("pausable");
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");
BADCVAR("g_start_delay");
BADCVAR("g_superspectate");
BADCVAR("g_tdm_teams_override");
+ BADCVAR("g_tmayhem_teams_override");
+ BADCVAR("g_tmayhem_powerups");
BADCVAR("g_weapon_stay"); BADPRESUFFIX("g_", "_weapon_stay");
BADCVAR("hostname");
BADCVAR("log_file");