]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Merge branch 'drjaska/mayhem' into z411/bai-server
authorz411 <z411@omaera.org>
Thu, 3 Feb 2022 16:40:59 +0000 (13:40 -0300)
committerz411 <z411@omaera.org>
Thu, 3 Feb 2022 16:40:59 +0000 (13:40 -0300)
gamemodes-server.cfg
qcsrc/common/gamemodes/gamemode/mayhem/mayhem.qh
qcsrc/common/gamemodes/gamemode/mayhem/sv_mayhem.qc
qcsrc/common/gamemodes/gamemode/mayhem/sv_mayhem.qh
qcsrc/common/gamemodes/gamemode/tmayhem/sv_tmayhem.qc
qcsrc/common/gamemodes/gamemode/tmayhem/sv_tmayhem.qh
qcsrc/common/gamemodes/gamemode/tmayhem/tmayhem.qh
qcsrc/server/world.qc

index f0654f656060e5cc1335c6705c9d1abd758cb78b..eb66d03c7257d8e1b0b3fd8360a4ab6e75a223b4 100644 (file)
@@ -614,11 +614,17 @@ set g_mmm_reward_detective 1 "give a point to all detective players if investiga
 // ==============================
 //  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"
@@ -633,12 +639,18 @@ set g_tmayhem_weaponarena "most_available" "starting weapons - takes the same op
 
 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"
index bf5568b84edbeff8402a97e00a908bb6773a43aa..19de29f035151685879278c2b977846a42a0b89e 100644 (file)
@@ -7,7 +7,7 @@
 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))
     {
@@ -22,6 +22,11 @@ CLASS(mayhem, Gametype)
                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)
index 70bd1dcf8476a71f378a51d3bdf6875a7219ad4a..ac5b4b6cd83bca3582ddb8988e4da00b085d29ea 100644 (file)
@@ -1,10 +1,32 @@
 #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)
 {
@@ -13,39 +35,47 @@ 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)
@@ -62,20 +92,34 @@ MUTATOR_HOOKFUNCTION(mayhem, SetWeaponArena)
 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)
@@ -91,114 +135,173 @@ 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;
+}
index 9393b311f70d2df3b1576a3c430466b52f46765a..69b2878dfd26e8fb53d547c075b562e8117cef4f 100644 (file)
@@ -1,10 +1,7 @@
 #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)
index acb10404e90fb35040ebb6cc17e18fc242c762aa..3ac2950d94c7ee51abd833af2852fc50d87bd46b 100644 (file)
@@ -1,16 +1,37 @@
 #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)
@@ -26,7 +47,7 @@ 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.");
 
@@ -47,16 +68,18 @@ void tmayhem_DelayedInit(entity this)
 
 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)
 {
@@ -65,29 +88,37 @@ 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)
@@ -104,20 +135,34 @@ MUTATOR_HOOKFUNCTION(tmayhem, SetWeaponArena)
 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)
@@ -128,125 +173,184 @@ 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;
+}
index d8dbcdf76df7646a090ba42616678cf1aaed39d1..c31967fad40db617df61c281f575b2b6bfb855ef 100644 (file)
@@ -1,12 +1,7 @@
 #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)
index 290881c9c921d509adbaa83a5aa401d417489cf0..dd4fa6e3782e9aab5de9eda4c53fa6d98725210a 100644 (file)
@@ -7,7 +7,7 @@
 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))
     {
@@ -43,7 +43,7 @@ CLASS(tmayhem, Gametype)
     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)
index 3b423f5dcc53a378d2471d2b090d00c674a366f1..446b198d951ec426de7afb86d73559cd24c3f0e0 100644 (file)
@@ -419,7 +419,11 @@ void cvar_changes_init()
                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");