// ==============================
// free for all and team mayhem
// ==============================
-set g_mayhem 0 "Mayhem: the player with the most frags in total mayhem wins"
-set g_tmayhem 0 "Team Mayhem: the team with the most frags in total mayhem wins"
-
-set g_mayhem_scoringmethod 1 "1: 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: 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 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_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_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"
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",_("The player with the most frags in total mayhem wins!"));
+ 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;
}
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, "fraglimit_override", 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)
#include "sv_mayhem.qh"
+#include <common/scores.qh>
+
+float autocvar_g_mayhem_fraglimit;
+float autocvar_g_mayhem_visual_score_limit;
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;
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)
{
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);
+ if (autocvar_fraglimit_override != 0)
+ GameRules_limit_score(autocvar_g_mayhem_visual_score_limit);
+ else
+ GameRules_limit_score(9999);
InitializeEntity(NULL, mayhem_DelayedInit, INITPRIO_GAMETYPE);
}
MUTATOR_HOOKFUNCTION(mayhem, Scores_CountFragsRemaining)
{
- // announce remaining frags
- return true;
+ // 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);
- start_health = warmup_start_health = cvar("g_mayhem_start_health");
- start_armorvalue = warmup_start_armorvalue = cvar("g_mayhem_start_armor");
- start_ammo_shells = warmup_start_ammo_shells = cvar("g_mayhem_start_ammo_shells");
- start_ammo_nails = warmup_start_ammo_nails = cvar("g_mayhem_start_ammo_nails");
- start_ammo_rockets = warmup_start_ammo_rockets = cvar("g_mayhem_start_ammo_rockets");
- start_ammo_cells = warmup_start_ammo_cells = cvar("g_mayhem_start_ammo_cells");
- start_ammo_plasma = warmup_start_ammo_plasma = cvar("g_mayhem_start_ammo_plasma");
- start_ammo_fuel = warmup_start_ammo_fuel = cvar("g_mayhem_start_ammo_fuel");
+ 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;
+ 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)
MUTATOR_HOOKFUNCTION(mayhem, FilterItem)
{
entity item = M_ARGV(0, entity);
- if (autocvar_g_powerups == 1){
- if (item.flags & FL_POWERUP){
+
+ //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;
}
}
- else if (autocvar_g_powerups == -1){
- if (item.flags & FL_POWERUP){
- if (autocvar_g_mayhem_powerups){
- 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;
}
}
- if (autocvar_g_pickup_items <= 0)
+ //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)
M_ARGV(4, float) = frag_damage;
}
-MUTATOR_HOOKFUNCTION(mayhem, PlayerDamage_SplitHealthArmor)
+void FFAMayhemCalculatePlayerScore(entity scorer)
{
- switch(autocvar_g_mayhem_scoringmethod)
+ if (autocvar_fraglimit_override > 0) autocvar_g_mayhem_fraglimit = autocvar_fraglimit_override;
+
+ switch (autocvar_g_mayhem_scoringmethod)
{
- //frags only
- case 2:
- {
- return;
- }
-
- //damage only
- case 3:
- {
- entity frag_attacker = M_ARGV(1, entity);
- entity frag_target = M_ARGV(2, 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);
-
- if (frag_target != frag_attacker && IS_PLAYER(frag_attacker))
- GameRules_scoring_add_team(frag_attacker, SCORE, (frag_damage - excess) * (1/(start_health + start_armorvalue)));
-
- if (frag_target == frag_attacker && IS_PLAYER(frag_attacker))
- GameRules_scoring_add_team(frag_target, SCORE, (-1 * (frag_damage - excess)) * (1/(start_health + start_armorvalue)));
-
- //handle hazard suiciding, check first if player has a registered attacker who most likely pushed them there
- if (!IS_PLAYER(frag_attacker) && (
- 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))
- GameRules_scoring_add_team(frag_target, SCORE, (-1 * (frag_damage - excess)) * (1/(start_health + start_armorvalue)));
-
- //when hp and armor values are checked when suiciding for some reason they are 0.9 hp and 0 armor regardless that player suicided with 200+200
- //AFAIK dynamic hp value checking is not possible, hardcoded start hp and armor
- //FIXME: ^ , might require fixing hp+a check for suicides as a whole
- if (frag_deathtype == DEATH_KILL.m_id)
- GameRules_scoring_add_team(frag_target, SCORE, (-1 * (start_health + start_armorvalue)) * (1/(start_health + start_armorvalue)));
- return;
- }
-
- //combined damage and frags
default:
case 1:
{
- entity frag_attacker = M_ARGV(1, entity);
- entity frag_target = M_ARGV(2, 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);
-
- if (frag_target != frag_attacker && IS_PLAYER(frag_attacker))
- GameRules_scoring_add_team(frag_attacker, SCORE, (frag_damage - excess) * 0.75 * mayhempointmultiplier * (1/(start_health + start_armorvalue)));
-
- if (frag_target == frag_attacker && IS_PLAYER(frag_attacker))
- GameRules_scoring_add_team(frag_target, SCORE, (-1 * (frag_damage - excess)) * 0.75 * mayhempointmultiplier * (1/(start_health + start_armorvalue)));
-
- //handle hazard suiciding, check first if player has a registered attacker who most likely pushed them there
- if (!IS_PLAYER(frag_attacker) && (
- 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))
- GameRules_scoring_add_team(frag_target, SCORE, (-1 * (frag_damage - excess)) * 0.75 * mayhempointmultiplier * (1/(start_health + start_armorvalue)));
-
- //when hp and armor values are checked when suiciding for some reason they are 0.9 hp and 0 armor regardless that player suicided with 200+200
- //AFAIK dynamic hp value checking is not possible, hardcoded start hp and armor
- //FIXME: ^ , might require fixing hp+a check for suicides as a whole
- if (frag_deathtype == DEATH_KILL.m_id)
- GameRules_scoring_add_team(frag_target, SCORE, (-1 * (start_health + start_armorvalue)) * 0.75 * mayhempointmultiplier * (1/(start_health + start_armorvalue)));
- return;
+ //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;
}
- }
-}
-MUTATOR_HOOKFUNCTION(mayhem, GiveFragsForKill, CBC_ORDER_FIRST)
-{
- switch(autocvar_g_mayhem_scoringmethod)
- {
- //frags only
case 2:
{
- //fix 999 score from 30 kills for example
- M_ARGV(2, float) = 1 * mayhempointmultiplier * 1.0001;
- return true;
+ //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;
}
-
- //damage only
+
case 3:
{
- M_ARGV(2, float) = 0;
- return true;
- }
-
- //combined damage and frags
- default:
- case 1:
- {
- M_ARGV(2, float) = 0.25 * mayhempointmultiplier * 1.0001;
- return true;
+ //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;
+}
#pragma once
#include <common/mutators/base.qh>
-//someone who understands numbers better check if 2 following floats can be ints without imprecision, I'm scared of spaghettimonsters
-float autocvar_g_mayhem_fraglimit;
-float autocvar_g_mayhem_visual_score_limit;
-float mayhempointmultiplier = 1000/30;
+
void mayhem_Initialize();
REGISTER_MUTATOR(mayhem, false)
#include "sv_tmayhem.qh"
-// TODO? rename to teammayhem? requires checking alias length
+float autocvar_g_tmayhem_fraglimit;
+float autocvar_g_tmayhem_visual_score_limit;
+float autocvar_g_tmayhem_score_leadlimit;
+bool autocvar_g_tmayhem_team_spawns;
+
+// 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;
+bool autocvar_g_tmayhem_rot;
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)
void tmayhem_DelayedInit(entity this)
{
// if no teams are found, spawn defaults
- if(find(NULL, classname, "tmayhem_team") == NULL)
+ if (find(NULL, classname, "tmayhem_team") == NULL)
{
LOG_TRACE("No \"tmayhem_team\" entities found on this map, creating them anyway.");
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);
+ if (autocvar_fraglimit_override != 0)
+ GameRules_limit_score(autocvar_g_tmayhem_visual_score_limit);
+ else
+ GameRules_limit_score(9999);
+
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)
{
MUTATOR_HOOKFUNCTION(tmayhem, Scores_CountFragsRemaining)
{
- // announce remaining frags
- return true;
+ // 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);
- start_health = warmup_start_health = cvar("g_tmayhem_start_health");
- start_armorvalue = warmup_start_armorvalue = cvar("g_tmayhem_start_armor");
- start_ammo_shells = warmup_start_ammo_shells = cvar("g_tmayhem_start_ammo_shells");
- start_ammo_nails = warmup_start_ammo_nails = cvar("g_tmayhem_start_ammo_nails");
- start_ammo_rockets = warmup_start_ammo_rockets = cvar("g_tmayhem_start_ammo_rockets");
- start_ammo_cells = warmup_start_ammo_cells = cvar("g_tmayhem_start_ammo_cells");
- start_ammo_plasma = warmup_start_ammo_plasma = cvar("g_tmayhem_start_ammo_plasma");
- start_ammo_fuel = warmup_start_ammo_fuel = cvar("g_tmayhem_start_ammo_fuel");
+ 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
MUTATOR_HOOKFUNCTION(tmayhem, PlayerRegen)
{
- if(autocvar_g_tmayhem_regenerate)
- return false;
- return true;
+ 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)
MUTATOR_HOOKFUNCTION(tmayhem, FilterItem)
{
entity item = M_ARGV(0, entity);
- if (autocvar_g_powerups == 1){
- if (item.flags & FL_POWERUP){
+
+ //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;
}
}
- else if (autocvar_g_powerups == -1){
- if (item.flags & FL_POWERUP){
- if (autocvar_g_tmayhem_powerups){
- 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;
}
}
- if (autocvar_g_pickup_items <= 0)
+ //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)
float frag_damage = M_ARGV(4, float);
float frag_mirrordamage = M_ARGV(5, float);
- if (IS_PLAYER(frag_target))
- if (!IS_DEAD(frag_target))
- if ((autocvar_g_tmayhem_selfdamage == 0 && frag_target == frag_attacker) || frag_deathtype == DEATH_FALL.m_id)
+ 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;
+ frag_mirrordamage = 0; //no mirror damaging
M_ARGV(4, float) = frag_damage;
M_ARGV(5, float) = frag_mirrordamage;
}
-MUTATOR_HOOKFUNCTION(tmayhem, PlayerDamage_SplitHealthArmor)
+void TeamMayhemCalculatePlayerScore(entity scorer)
{
- switch(autocvar_g_tmayhem_scoringmethod)
+ if (autocvar_fraglimit_override > 0) autocvar_g_tmayhem_fraglimit = autocvar_fraglimit_override;
+
+ switch (autocvar_g_tmayhem_scoringmethod)
{
- //frags only
- case 2:
- {
- return;
- }
-
- //damage only
- case 3:
- {
- entity frag_attacker = M_ARGV(1, entity);
- entity frag_target = M_ARGV(2, 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);
-
- if (frag_target != frag_attacker && IS_PLAYER(frag_attacker))
- GameRules_scoring_add_team(frag_attacker, SCORE, (frag_damage - excess) * (1/(start_health + start_armorvalue)));
-
- if (frag_target == frag_attacker && IS_PLAYER(frag_attacker))
- GameRules_scoring_add_team(frag_target, SCORE, (-1 * (frag_damage - excess)) * (1/(start_health + start_armorvalue)));
-
- //handle hazard suiciding, check first if player has a registered attacker who most likely pushed them there
- if (!IS_PLAYER(frag_attacker) && (
- 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))
- GameRules_scoring_add_team(frag_target, SCORE, (-1 * (frag_damage - excess)) * (1/(start_health + start_armorvalue)));
-
- //when hp and armor values are checked when suiciding for some reason they are 0.9 hp and 0 armor regardless that player suicided with 200+200
- //AFAIK dynamic hp value checking is not possible, hardcoded start hp and armor
- //FIXME: ^ , might require fixing hp+a check for suicides as a whole
- if (frag_deathtype == DEATH_KILL.m_id)
- GameRules_scoring_add_team(frag_target, SCORE, (-1 * (start_health + start_armorvalue)) * (1/(start_health + start_armorvalue)));
- return;
- }
-
- //combined damage and frags
default:
case 1:
{
- entity frag_attacker = M_ARGV(1, entity);
- entity frag_target = M_ARGV(2, 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);
-
- if (frag_target != frag_attacker && IS_PLAYER(frag_attacker))
- GameRules_scoring_add_team(frag_attacker, SCORE, (frag_damage - excess) * 0.75 * tmayhempointmultiplier * (1/(start_health + start_armorvalue)));
-
- if (frag_target == frag_attacker && IS_PLAYER(frag_attacker))
- GameRules_scoring_add_team(frag_target, SCORE, (-1 * (frag_damage - excess)) * 0.75 * tmayhempointmultiplier * (1/(start_health + start_armorvalue)));
-
- //handle hazard suiciding, check first if player has a registered attacker who most likely pushed them there
- if (!IS_PLAYER(frag_attacker) && (
- 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))
- GameRules_scoring_add_team(frag_target, SCORE, (-1 * (frag_damage - excess)) * 0.75 * tmayhempointmultiplier * (1/(start_health + start_armorvalue)));
-
- //when hp and armor values are checked when suiciding for some reason they are 0.9 hp and 0 armor regardless that player suicided with 200+200
- //AFAIK dynamic hp value checking is not possible, hardcoded start hp and armor
- //FIXME: ^ , might require fixing hp+a check for suicides as a whole
- if (frag_deathtype == DEATH_KILL.m_id)
- GameRules_scoring_add_team(frag_target, SCORE, (-1 * (start_health + start_armorvalue)) * 0.75 * tmayhempointmultiplier * (1/(start_health + start_armorvalue)));
- return;
+ //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;
}
- }
-}
-MUTATOR_HOOKFUNCTION(tmayhem, GiveFragsForKill, CBC_ORDER_FIRST)
-{
- switch(autocvar_g_tmayhem_scoringmethod)
- {
- //frags only
case 2:
{
- //fix 999 score from 30 kills for example
- M_ARGV(2, float) = 1 * tmayhempointmultiplier * 1.0001;
- return true;
+ //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;
}
-
- //damage only
+
case 3:
{
- M_ARGV(2, float) = 0;
- return true;
- }
-
- //combined damage and frags
- default:
- case 1:
- {
- M_ARGV(2, float) = 0.25 * tmayhempointmultiplier * 1.0001;
- return true;
+ //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;
+}
#pragma once
#include <common/mutators/base.qh>
-//someone who understands numbers better check if 2 following floats can be ints without imprecision, I'm scared of spaghettimonsters
-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 = 1000/50;
+
void tmayhem_Initialize();
REGISTER_MUTATOR(tmayhem, false)
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",_("The team with the most frags in total mayhem wins!"));
+ 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))
{
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:"), 5, 100, 5, "g_tmayhem_point_limit", "g_tmayhem_teams_override", _("The amount of points needed before the match will end"));
+ returns(menu, _("Frag limit:"), 5, 100, 5, "fraglimit_override", "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)
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");