]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/server/g_damage.qc
Check for the sound hittype instead of the tuba when deciding whether to send damage...
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / g_damage.qc
index cfdc00c57740fe411ae1e78c18d71657065bc125..9eb3d86eb65834cd10dd2784657b260b56ed1ef4 100644 (file)
@@ -3,6 +3,7 @@
 #include <common/effects/all.qh>
 #include "bot/api.qh"
 #include "g_hook.qh"
+#include <server/gamelog.qh>
 #include <server/mutators/_mod.qh>
 #include "teamplay.qh"
 #include "scores.qh"
@@ -26,6 +27,7 @@
 #include "../common/playerstats.qh"
 #include "../common/teams.qh"
 #include "../common/util.qh"
+#include <common/gamemodes/_mod.qh>
 #include <common/gamemodes/rules.qh>
 #include <common/weapons/_all.qh>
 #include "../lib/csqcmodel/sv_model.qh"
@@ -74,8 +76,6 @@ void GiveFrags(entity attacker, entity targ, float f, int deathtype, .entity wea
                UpdateFrags(attacker, f);
 }
 
-.entity kh_next;
-
 string AppendItemcodes(string s, entity player)
 {
        for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
@@ -87,16 +87,15 @@ string AppendItemcodes(string s, entity player)
                if(w != 0 || slot == 0)
                        s = strcat(s, ftos(w));
        }
-       if(time < player.strength_finished)
+       if(time < STAT(STRENGTH_FINISHED, player))
                s = strcat(s, "S");
-       if(time < player.invincible_finished)
+       if(time < STAT(INVINCIBLE_FINISHED, player))
                s = strcat(s, "I");
-       if(player.flagcarried != NULL)
-               s = strcat(s, "F");
        if(PHYS_INPUT_BUTTON_CHAT(player))
                s = strcat(s, "T");
-       if(player.kh_next)
-               s = strcat(s, "K");
+       // TODO: include these codes as a flag on the item itself
+       MUTATOR_CALLHOOK(LogDeath_AppendItemCodes, player, s);
+       s = M_ARGV(1, string);
        return s;
 }
 
@@ -132,7 +131,7 @@ void Obituary_SpecialDeath(
                return;
        }
 
-       entity deathent = Deathtypes_from(deathtype - DT_FIRST);
+       entity deathent = REGISTRY_GET(Deathtypes, deathtype - DT_FIRST);
        if (!deathent)
        {
                backtrace("Obituary_SpecialDeath: Could not find deathtype entity!\n");
@@ -202,21 +201,21 @@ float Obituary_WeaponDeath(
        else
        {
                LOG_TRACEF(
-                       "Obituary_WeaponDeath(): ^1Deathtype ^7(%d)^1 has no notification for weapon %d!\n",
+                       "Obituary_WeaponDeath(): ^1Deathtype ^7(%d)^1 has no notification for weapon %s!\n",
                        deathtype,
-                       death_weapon
+                       death_weapon.netname
                );
        }
 
        return true;
 }
 
-bool frag_centermessage_override(entity attacker, entity targ, int deathtype, int kill_count_to_attacker, int kill_count_to_target)
+bool frag_centermessage_override(entity attacker, entity targ, int deathtype, int kill_count_to_attacker, int kill_count_to_target, string attacker_name)
 {
        if(deathtype == DEATH_FIRE.m_id)
        {
                Send_Notification(NOTIF_ONE, attacker, MSG_CHOICE, CHOICE_FRAG_FIRE, targ.netname, kill_count_to_attacker, (IS_BOT_CLIENT(targ) ? -1 : CS(targ).ping));
-               Send_Notification(NOTIF_ONE, targ, MSG_CHOICE, CHOICE_FRAGGED_FIRE, attacker.netname, kill_count_to_target, GetResourceAmount(attacker, RESOURCE_HEALTH), GetResourceAmount(attacker, RESOURCE_ARMOR), (IS_BOT_CLIENT(attacker) ? -1 : CS(attacker).ping));
+               Send_Notification(NOTIF_ONE, targ, MSG_CHOICE, CHOICE_FRAGGED_FIRE, attacker_name, kill_count_to_target, GetResource(attacker, RES_HEALTH), GetResource(attacker, RES_ARMOR), (IS_BOT_CLIENT(attacker) ? -1 : CS(attacker).ping));
                return true;
        }
 
@@ -231,16 +230,25 @@ void Obituary(entity attacker, entity inflictor, entity targ, int deathtype, .en
        // Declarations
        float notif_firstblood = false;
        float kill_count_to_attacker, kill_count_to_target;
+       bool notif_anonymous = false;
+       string attacker_name = attacker.netname;
 
        // Set final information for the death
        targ.death_origin = targ.origin;
        string deathlocation = (autocvar_notification_server_allows_location ? NearestLocation(targ.death_origin) : "");
 
+       // Abort now if a mutator requests it
+       if (MUTATOR_CALLHOOK(ClientObituary, inflictor, attacker, targ, deathtype, attacker.(weaponentity))) { CS(targ).killcount = 0; return; }
+       notif_anonymous = M_ARGV(5, bool);
+
+       if(notif_anonymous)
+               attacker_name = "Anonymous player";
+
        #ifdef NOTIFICATIONS_DEBUG
        Debug_Notification(
                sprintf(
                        "Obituary(%s, %s, %s, %s = %d);\n",
-                       attacker.netname,
+                       attacker_name,
                        inflictor.netname,
                        targ.netname,
                        Deathtype_Name(deathtype),
@@ -301,8 +309,8 @@ void Obituary(entity attacker, entity inflictor, entity targ, int deathtype, .en
                        CS(attacker).killcount = 0;
 
                        Send_Notification(NOTIF_ONE, attacker, MSG_CENTER, CENTER_DEATH_TEAMKILL_FRAG, targ.netname);
-                       Send_Notification(NOTIF_ONE, targ, MSG_CENTER, CENTER_DEATH_TEAMKILL_FRAGGED, attacker.netname);
-                       Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(targ.team, INFO_DEATH_TEAMKILL), targ.netname, attacker.netname, deathlocation, CS(targ).killcount);
+                       Send_Notification(NOTIF_ONE, targ, MSG_CENTER, CENTER_DEATH_TEAMKILL_FRAGGED, attacker_name);
+                       Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(targ.team, INFO_DEATH_TEAMKILL), targ.netname, attacker_name, deathlocation, CS(targ).killcount);
 
                        // In this case, the death message will ALWAYS be "foo was betrayed by bar"
                        // No need for specific death/weapon messages...
@@ -321,14 +329,11 @@ void Obituary(entity attacker, entity inflictor, entity targ, int deathtype, .en
                        // these 2 macros are spread over multiple files
                        #define SPREE_ITEM(counta,countb,center,normal,gentle) \
                                case counta: \
-                               { \
                                        Send_Notification(NOTIF_ONE, attacker, MSG_ANNCE, ANNCE_KILLSTREAK_##countb); \
-                                       if (!warmup_stage)\
-                                       {\
+                                       if (!warmup_stage) \
                                                PlayerStats_GameReport_Event_Player(attacker, PLAYERSTATS_ACHIEVEMENT_KILL_SPREE_##counta, 1); \
-                                       }\
-                                       break; \
-                               }
+                                       break;
+
                        switch(CS(attacker).killcount)
                        {
                                KILL_SPREE_LIST
@@ -369,14 +374,14 @@ void Obituary(entity attacker, entity inflictor, entity targ, int deathtype, .en
                                        targ,
                                        MSG_CHOICE,
                                        CHOICE_TYPEFRAGGED,
-                                       attacker.netname,
+                                       attacker_name,
                                        kill_count_to_target,
-                                       GetResourceAmount(attacker, RESOURCE_HEALTH),
-                                       GetResourceAmount(attacker, RESOURCE_ARMOR),
+                                       GetResource(attacker, RES_HEALTH),
+                                       GetResource(attacker, RES_ARMOR),
                                        (IS_BOT_CLIENT(attacker) ? -1 : CS(attacker).ping)
                                );
                        }
-                       else if(!frag_centermessage_override(attacker, targ, deathtype, kill_count_to_attacker, kill_count_to_target))
+                       else if(!frag_centermessage_override(attacker, targ, deathtype, kill_count_to_attacker, kill_count_to_target, attacker_name))
                        {
                                Send_Notification(
                                        NOTIF_ONE,
@@ -392,10 +397,10 @@ void Obituary(entity attacker, entity inflictor, entity targ, int deathtype, .en
                                        targ,
                                        MSG_CHOICE,
                                        CHOICE_FRAGGED,
-                                       attacker.netname,
+                                       attacker_name,
                                        kill_count_to_target,
-                                       GetResourceAmount(attacker, RESOURCE_HEALTH),
-                                       GetResourceAmount(attacker, RESOURCE_ARMOR),
+                                       GetResource(attacker, RES_HEALTH),
+                                       GetResource(attacker, RES_ARMOR),
                                        (IS_BOT_CLIENT(attacker) ? -1 : CS(attacker).ping)
                                );
                        }
@@ -404,8 +409,8 @@ void Obituary(entity attacker, entity inflictor, entity targ, int deathtype, .en
                        if(deathtype == DEATH_BUFF.m_id)
                                f3 = buff_FirstFromFlags(STAT(BUFFS, attacker)).m_id;
 
-                       if (!Obituary_WeaponDeath(targ, true, deathtype, targ.netname, attacker.netname, deathlocation, CS(targ).killcount, kill_count_to_attacker))
-                               Obituary_SpecialDeath(targ, true, deathtype, targ.netname, attacker.netname, deathlocation, CS(targ).killcount, kill_count_to_attacker, f3);
+                       if (!Obituary_WeaponDeath(targ, true, deathtype, targ.netname, attacker_name, deathlocation, CS(targ).killcount, kill_count_to_attacker))
+                               Obituary_SpecialDeath(targ, true, deathtype, targ.netname, attacker_name, deathlocation, CS(targ).killcount, kill_count_to_attacker, f3);
                }
        }
 
@@ -474,7 +479,9 @@ void Ice_Think(entity this)
                delete(this);
                return;
        }
-       setorigin(this, this.owner.origin - '0 0 16');
+       vector ice_org = this.owner.origin - '0 0 16';
+       if (this.origin != ice_org)
+               setorigin(this, ice_org);
        this.nextthink = time;
 }
 
@@ -490,7 +497,7 @@ void Freeze(entity targ, float revivespeed, int frozen_type, bool show_waypoint)
 
        STAT(FROZEN, targ) = frozen_type;
        STAT(REVIVE_PROGRESS, targ) = ((frozen_type == FROZEN_TEMP_DYING) ? 1 : 0);
-       SetResourceAmount(targ, RESOURCE_HEALTH, ((frozen_type == FROZEN_TEMP_DYING) ? targ_maxhealth : 1));
+       SetResource(targ, RES_HEALTH, ((frozen_type == FROZEN_TEMP_DYING) ? targ_maxhealth : 1));
        targ.revive_speed = revivespeed;
        if(targ.bot_attack)
                IL_REMOVE(g_bot_targets, targ);
@@ -500,6 +507,7 @@ void Freeze(entity targ, float revivespeed, int frozen_type, bool show_waypoint)
        entity ice = new(ice);
        ice.owner = targ;
        ice.scale = targ.scale;
+       // set_movetype(ice, MOVETYPE_FOLLOW) would rotate the ice model with the player
        setthink(ice, Ice_Think);
        ice.nextthink = time;
        ice.frame = floor(random() * 21); // ice model has 20 different looking frames
@@ -535,7 +543,7 @@ void Unfreeze(entity targ, bool reset_health)
                return;
 
        if (reset_health && STAT(FROZEN, targ) != FROZEN_TEMP_DYING)
-               SetResourceAmount(targ, RESOURCE_HEALTH, ((IS_PLAYER(targ)) ? start_health : targ.max_health));
+               SetResource(targ, RES_HEALTH, ((IS_PLAYER(targ)) ? start_health : targ.max_health));
 
        targ.pauseregen_finished = time + autocvar_g_balance_pause_health_regen;
 
@@ -595,9 +603,9 @@ void Damage(entity targ, entity inflictor, entity attacker, float damage, int de
                // These are ALWAYS lethal
                // No damage modification here
                // Instead, prepare the victim for his death...
-               SetResourceAmount(targ, RESOURCE_ARMOR, 0);
+               SetResourceExplicit(targ, RES_ARMOR, 0);
                targ.spawnshieldtime = 0;
-               SetResourceAmount(targ, RESOURCE_HEALTH, 0.9); // this is < 1
+               SetResourceExplicit(targ, RES_HEALTH, 0.9); // this is < 1
                targ.flags -= targ.flags & FL_GODMODE;
                damage = 100000;
        }
@@ -622,7 +630,15 @@ void Damage(entity targ, entity inflictor, entity attacker, float damage, int de
                                        damage = 0;
                                else if(attacker != targ)
                                {
-                                       if(autocvar_teamplay_mode == 3)
+                                       if(autocvar_teamplay_mode == 2)
+                                       {
+                                               if(IS_PLAYER(targ) && !IS_DEAD(targ))
+                                               {
+                                                       attacker.dmg_team = attacker.dmg_team + damage;
+                                                       complainteamdamage = attacker.dmg_team - autocvar_g_teamdamage_threshold;
+                                               }
+                                       }
+                                       else if(autocvar_teamplay_mode == 3)
                                                damage = 0;
                                        else if(autocvar_teamplay_mode == 4)
                                        {
@@ -638,7 +654,7 @@ void Damage(entity targ, entity inflictor, entity attacker, float damage, int de
 
                                                        if(autocvar_g_mirrordamage_virtual)
                                                        {
-                                                               vector v  = healtharmor_applydamage(GetResourceAmount(attacker, RESOURCE_ARMOR), autocvar_g_balance_armor_blockpercent, deathtype, mirrordamage);
+                                                               vector v  = healtharmor_applydamage(GetResource(attacker, RES_ARMOR), autocvar_g_balance_armor_blockpercent, deathtype, mirrordamage);
                                                                attacker.dmg_take += v.x;
                                                                attacker.dmg_save += v.y;
                                                                attacker.dmg_inflictor = inflictor;
@@ -648,7 +664,7 @@ void Damage(entity targ, entity inflictor, entity attacker, float damage, int de
 
                                                        if(autocvar_g_friendlyfire_virtual)
                                                        {
-                                                               vector v = healtharmor_applydamage(GetResourceAmount(targ, RESOURCE_ARMOR), autocvar_g_balance_armor_blockpercent, deathtype, damage);
+                                                               vector v = healtharmor_applydamage(GetResource(targ, RES_ARMOR), autocvar_g_balance_armor_blockpercent, deathtype, damage);
                                                                targ.dmg_take += v.x;
                                                                targ.dmg_save += v.y;
                                                                targ.dmg_inflictor = inflictor;
@@ -689,12 +705,13 @@ void Damage(entity targ, entity inflictor, entity attacker, float damage, int de
                    }
                }
 
-               if(deathtype != DEATH_HURTTRIGGER.m_id && deathtype != DEATH_TEAMCHANGE.m_id && deathtype != DEATH_AUTOTEAMCHANGE.m_id && STAT(FROZEN, targ))
+               if(STAT(FROZEN, targ) && !ITEM_DAMAGE_NEEDKILL(deathtype)
+                       && deathtype != DEATH_TEAMCHANGE.m_id && deathtype != DEATH_AUTOTEAMCHANGE.m_id)
                {
                        if(autocvar_g_frozen_revive_falldamage > 0 && deathtype == DEATH_FALL.m_id && damage >= autocvar_g_frozen_revive_falldamage)
                        {
                                Unfreeze(targ, false);
-                               SetResourceAmount(targ, RESOURCE_HEALTH, autocvar_g_frozen_revive_falldamage_health);
+                               SetResource(targ, RES_HEALTH, autocvar_g_frozen_revive_falldamage_health);
                                Send_Effect(EFFECT_ICEORGLASS, targ.origin, '0 0 0', 3);
                                Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_FREEZETAG_REVIVED_FALL, targ.netname);
                                Send_Notification(NOTIF_ONE, targ, MSG_CENTER, CENTER_FREEZETAG_REVIVE_SELF);
@@ -704,12 +721,12 @@ void Damage(entity targ, entity inflictor, entity attacker, float damage, int de
                        force *= autocvar_g_frozen_force;
                }
 
-               if(IS_PLAYER(targ) && STAT(FROZEN, targ) && deathtype == DEATH_HURTTRIGGER.m_id && !autocvar_g_frozen_damage_trigger)
+               if(IS_PLAYER(targ) && STAT(FROZEN, targ)
+                       && ITEM_DAMAGE_NEEDKILL(deathtype) && !autocvar_g_frozen_damage_trigger)
                {
                        Send_Effect(EFFECT_TELEPORT, targ.origin, '0 0 0', 1);
 
-                       entity spot = SelectSpawnPoint (targ, false);
-
+                       entity spot = SelectSpawnPoint(targ, false);
                        if(spot)
                        {
                                damage = 0;
@@ -844,7 +861,7 @@ void Damage(entity targ, entity inflictor, entity attacker, float damage, int de
                        farcent.nextthink = time + 0.1;
                        setthink(farcent, SUB_Remove);
                }
-               else
+               else if(targ.move_movetype != MOVETYPE_NOCLIP)
                {
                        targ.velocity = targ.velocity + farce;
                }
@@ -868,7 +885,7 @@ void Damage(entity targ, entity inflictor, entity attacker, float damage, int de
 }
 
 float RadiusDamageForSource (entity inflictor, vector inflictororigin, vector inflictorvelocity, entity attacker, float coredamage, float edgedamage, float rad, entity cantbe, entity mustbe,
-                                                               float inflictorselfdamage, float forceintensity, int deathtype, .entity weaponentity, entity directhitentity)
+                                                               float inflictorselfdamage, float forceintensity, float forcezscale, int deathtype, .entity weaponentity, entity directhitentity)
        // Returns total damage applies to creatures
 {
        entity  targ;
@@ -894,7 +911,7 @@ float RadiusDamageForSource (entity inflictor, vector inflictororigin, vector in
        total_damage_to_creatures = 0;
 
        if(deathtype != (WEP_HOOK.m_id | HITTYPE_SECONDARY | HITTYPE_BOUNCE)) // only send gravity bomb damage once
-               if(DEATH_WEAPONOF(deathtype) != WEP_TUBA) // do not send tuba damage (bandwidth hog)
+               if(!(deathtype & HITTYPE_SOUND)) // do not send radial sound damage (bandwidth hog)
                {
                        force = inflictorvelocity;
                        if(force == '0 0 0')
@@ -955,8 +972,10 @@ float RadiusDamageForSource (entity inflictor, vector inflictororigin, vector in
                                        force = force * (finaldmg / coredamage) * forceintensity;
                                        hitloc = nearest;
 
-                                       if(deathtype & WEP_BLASTER.m_id)
-                                               force *= WEP_CVAR_BOTH(blaster, !(deathtype & HITTYPE_SECONDARY), force_zscale);
+                                       // apply special scaling along the z axis if set
+                                       // NOTE: 0 value is not allowed for compatibility, in the case of weapon cvars not being set
+                                       if(forcezscale)
+                                               force.z *= forcezscale;
 
                                        if(targ != directhitentity)
                                        {
@@ -1059,7 +1078,8 @@ float RadiusDamageForSource (entity inflictor, vector inflictororigin, vector in
 
 float RadiusDamage(entity inflictor, entity attacker, float coredamage, float edgedamage, float rad, entity cantbe, entity mustbe, float forceintensity, int deathtype, .entity weaponentity, entity directhitentity)
 {
-       return RadiusDamageForSource(inflictor, (inflictor.origin + (inflictor.mins + inflictor.maxs) * 0.5), inflictor.velocity, attacker, coredamage, edgedamage, rad, cantbe, mustbe, false, forceintensity, deathtype, weaponentity, directhitentity);
+       return RadiusDamageForSource(inflictor, (inflictor.origin + (inflictor.mins + inflictor.maxs) * 0.5), inflictor.velocity, attacker, coredamage, edgedamage, rad, 
+                                                                       cantbe, mustbe, false, forceintensity, 1, deathtype, weaponentity, directhitentity);
 }
 
 bool Heal(entity targ, entity inflictor, float amount, float limit)