]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/common/mutators/mutator/nades/nades.qc
Show nade throw message when it explodes while holding it in hand.
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / mutators / mutator / nades / nades.qc
index 9e0f50d925875eca3575cd78d9993b58d4ef6bdc..67e3d4ad1c02ccb86afa812b194ada6bf25e43c2 100644 (file)
@@ -10,6 +10,9 @@ float autocvar_g_nades_spread = 0.04;
 REGISTER_STAT(NADES_SMALL, int, autocvar_g_nades_nade_small)
 
 #ifdef GAMEQC
+REPLICATE(cvar_cl_nade_type, int, "cl_nade_type");
+REPLICATE(cvar_cl_pokenade_type, string, "cl_pokenade_type");
+
 entity Nade_TrailEffect(int proj, int nade_team)
 {
     switch (proj)
@@ -158,7 +161,6 @@ void DrawAmmoNades(vector myPos, vector mySize, bool draw_expanding, float expan
 #include <common/gamemodes/_mod.qh>
 #include <common/monsters/sv_spawn.qh>
 #include <common/monsters/sv_monsters.qh>
-#include <server/g_subs.qh>
 
 REGISTER_MUTATOR(nades, autocvar_g_nades);
 
@@ -384,7 +386,7 @@ void nade_ice_freeze(entity freezefield, entity frost_target, float freezetime)
 {
        frost_target.frozen_by = freezefield.realowner;
        Send_Effect(EFFECT_ELECTRO_IMPACT, frost_target.origin, '0 0 0', 1);
-       Freeze(frost_target, 1 / freezetime, 3, false);
+       Freeze(frost_target, 1 / freezetime, FROZEN_TEMP_DYING, false);
 
        Drop_Special_Items(frost_target);
 }
@@ -441,7 +443,7 @@ void nade_ice_think(entity this)
 
        float current_freeze_time = this.ltime - time - 0.1;
 
-       FOREACH_ENTITY_RADIUS(this.origin, autocvar_g_nades_nade_radius, it != this && it.takedamage && !IS_DEAD(it) && GetResourceAmount(it, RESOURCE_HEALTH) > 0 && current_freeze_time > 0,
+       FOREACH_ENTITY_RADIUS(this.origin, autocvar_g_nades_nade_radius, it != this && it.takedamage && !IS_DEAD(it) && GetResource(it, RES_HEALTH) > 0 && current_freeze_time > 0,
        {
                if(!autocvar_g_nades_ice_teamcheck || (DIFF_TEAM(it, this.realowner) || it == this.realowner))
                if(!it.revival_time || ((time - it.revival_time) >= 1.5))
@@ -633,14 +635,14 @@ void nade_heal_touch(entity this, entity toucher)
                if ( health_factor > 0 )
                {
                        maxhealth = (IS_MONSTER(toucher)) ? toucher.max_health : g_pickup_healthmega_max;
-                       float hp = GetResourceAmount(toucher, RESOURCE_HEALTH);
+                       float hp = GetResource(toucher, RES_HEALTH);
                        if (hp < maxhealth)
                        {
                                if (this.nade_show_particles)
                                {
                                        Send_Effect(EFFECT_HEALING, toucher.origin, '0 0 0', 1);
                                }
-                               GiveResourceWithLimit(toucher, RESOURCE_HEALTH, health_factor, maxhealth);
+                               GiveResourceWithLimit(toucher, RES_HEALTH, health_factor, maxhealth);
                        }
                }
                else if ( health_factor < 0 )
@@ -815,7 +817,7 @@ void nade_touch(entity this, entity toucher)
 
        if(autocvar_g_nades_pickup)
        if(time >= this.spawnshieldtime)
-       if(!toucher.nade && GetResourceAmount(this, RESOURCE_HEALTH) == this.max_health) // no boosted shot pickups, thank you very much
+       if(!toucher.nade && GetResource(this, RES_HEALTH) == this.max_health) // no boosted shot pickups, thank you very much
        if(CanThrowNade(toucher)) // prevent some obvious things, like dead players
        if(IS_REAL_CLIENT(toucher)) // above checks for IS_PLAYER, don't need to do it here
        {
@@ -843,7 +845,7 @@ void nade_touch(entity this, entity toucher)
 
        //setsize(this, '-2 -2 -2', '2 2 2');
        //UpdateCSQCProjectile(this);
-       if(GetResourceAmount(this, RESOURCE_HEALTH) == this.max_health)
+       if(GetResource(this, RES_HEALTH) == this.max_health)
        {
                spamsound(this, CH_SHOTS, SND_GRENADE_BOUNCE_RANDOM(), VOL_BASE, ATTEN_NORM);
                return;
@@ -892,22 +894,25 @@ void nade_damage(entity this, entity inflictor, entity attacker, float damage, i
                damage = this.max_health * 0.1;
        else if(DEATH_ISWEAPON(deathtype, WEP_SHOCKWAVE) || DEATH_ISWEAPON(deathtype, WEP_SHOTGUN)) // WEAPONTODO
        {
-               if(deathtype & HITTYPE_SECONDARY)
-               {
-                       damage = this.max_health * 0.1;
-                       force *= 10;
-               }
-               else
+               if(!(deathtype & HITTYPE_SECONDARY))
                        damage = this.max_health * 1.15;
        }
 
+       // melee slaps
+       entity death_weapon = DEATH_WEAPONOF(deathtype);
+       if(((deathtype & HITTYPE_SECONDARY) ? (death_weapon.spawnflags & WEP_TYPE_MELEE_SEC) : (death_weapon.spawnflags & WEP_TYPE_MELEE_PRI)))
+       {
+               damage = this.max_health * 0.1;
+               force *= 10;
+       }
+
        this.velocity += force;
        UpdateCSQCProjectile(this);
 
        if(damage <= 0 || ((IS_ONGROUND(this)) && IS_PLAYER(attacker)))
                return;
 
-       float hp = GetResourceAmount(this, RESOURCE_HEALTH);
+       float hp = GetResource(this, RES_HEALTH);
        if(hp == this.max_health)
        {
                sound(this, CH_SHOTS_SINGLE, SND_Null, VOL_BASE, 0.5 *(ATTEN_LARGE + ATTEN_MAX));
@@ -916,7 +921,7 @@ void nade_damage(entity this, entity inflictor, entity attacker, float damage, i
        }
 
        hp -= damage;
-       SetResourceAmount(this, RESOURCE_HEALTH, hp);
+       SetResource(this, RES_HEALTH, hp);
 
 
        if ( STAT(NADE_BONUS_TYPE, this) != NADE_TYPE_HEAL.m_id || IS_PLAYER(attacker) )
@@ -978,8 +983,8 @@ void toss_nade(entity e, bool set_owner, vector _velocity, float _time)
 
        settouch(_nade, nade_touch);
        _nade.spawnshieldtime = time + 0.1; // prevent instantly picking up again
-       SetResourceAmount(_nade, RESOURCE_HEALTH, autocvar_g_nades_nade_health);
-       _nade.max_health = _nade.health;
+       SetResource(_nade, RES_HEALTH, autocvar_g_nades_nade_health);
+       _nade.max_health = GetResource(_nade, RES_HEALTH);
        _nade.takedamage = DAMAGE_AIM;
        _nade.event_damage = nade_damage;
        setcefc(_nade, func_null);
@@ -1022,7 +1027,7 @@ void nades_GiveBonus(entity player, float score)
        if (autocvar_g_nades_bonus)
        if (IS_REAL_CLIENT(player))
        if (IS_PLAYER(player) && STAT(NADE_BONUS, player) < autocvar_g_nades_bonus_max)
-       if (STAT(FROZEN, player) == 0)
+       if (!STAT(FROZEN, player))
        if (!IS_DEAD(player))
        {
                if ( STAT(NADE_BONUS_SCORE, player) < 1 )
@@ -1031,7 +1036,7 @@ void nades_GiveBonus(entity player, float score)
                if ( STAT(NADE_BONUS_SCORE, player) >= 1 )
                {
                        Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_NADE_BONUS);
-                       play2(player, SND(KH_ALARM));
+                       play2(player, SND(NADE_BONUS));
                        STAT(NADE_BONUS, player)++;
                        STAT(NADE_BONUS_SCORE, player) -= 1;
                }
@@ -1104,7 +1109,8 @@ void spawn_held_nade(entity player, entity nowner, float ntime, int ntype, strin
        n.alpha = Nades_from(STAT(NADE_BONUS_TYPE, n)).m_alpha;
 
        setmodel(fn, MDL_NADE_VIEW);
-       setattachment(fn, player.(weaponentity), "");
+       //setattachment(fn, player.(weaponentity), "");
+       fn.viewmodelforclient = player;
        fn.realowner = fn.owner = player;
        fn.colormod = Nades_from(STAT(NADE_BONUS_TYPE, n)).m_color;
        fn.colormap = player.colormap;
@@ -1161,7 +1167,7 @@ bool CanThrowNade(entity this)
        if (!autocvar_g_nades)
                return false; // allow turning them off mid match
 
-       if(forbidWeaponUse(this))
+       if (weaponLocked(this))
                return false;
 
        if (!IS_PLAYER(this))
@@ -1183,7 +1189,6 @@ void nades_CheckThrow(entity this)
                this.nade_altbutton = true;
                if(time > this.nade_refire)
                {
-                       Send_Notification(NOTIF_ONE, this, MSG_CENTER, CENTER_NADE_THROW);
                        nade_prime(this);
                        this.nade_refire = time + autocvar_g_nades_nade_refire;
                }
@@ -1247,25 +1252,35 @@ CLASS(NadeOffhand, OffhandWeapon)
                }
     }
 ENDCLASS(NadeOffhand)
-NadeOffhand OFFHAND_NADE; STATIC_INIT(OFFHAND_NADE) { OFFHAND_NADE = NEW(NadeOffhand); }
+NadeOffhand OFFHAND_NADE;
+STATIC_INIT(OFFHAND_NADE) { OFFHAND_NADE = NEW(NadeOffhand); }
 
 MUTATOR_HOOKFUNCTION(nades, ForbidThrowCurrentWeapon, CBC_ORDER_LAST)
 {
     entity player = M_ARGV(0, entity);
 
-       if (player.offhand != OFFHAND_NADE || (player.weapons & WEPSET(HOOK)) || autocvar_g_nades_override_dropweapon) {
+       if (player.offhand != OFFHAND_NADE || (STAT(WEAPONS, player) & WEPSET(HOOK)) || autocvar_g_nades_override_dropweapon) {
                nades_CheckThrow(player);
                return true;
        }
 }
 
+#ifdef IS_REVIVING
+       #undef IS_REVIVING
+#endif
+
+// returns true if player is reviving it
+#define IS_REVIVING(player, it, revive_extra_size) \
+       (it != player && !STAT(FROZEN, it) && !IS_DEAD(it) && SAME_TEAM(it, player) \
+       && boxesoverlap(player.absmin - revive_extra_size, player.absmax + revive_extra_size, it.absmin, it.absmax))
+
 MUTATOR_HOOKFUNCTION(nades, PlayerPreThink)
 {
        entity player = M_ARGV(0, entity);
 
        if (!IS_PLAYER(player)) { return; }
 
-       if (player.nade && (player.offhand != OFFHAND_NADE || (player.weapons & WEPSET(HOOK)))) OFFHAND_NADE.offhand_think(OFFHAND_NADE, player, player.nade_altbutton);
+       if (player.nade && (player.offhand != OFFHAND_NADE || (STAT(WEAPONS, player) & WEPSET(HOOK)))) OFFHAND_NADE.offhand_think(OFFHAND_NADE, player, player.nade_altbutton);
 
        entity held_nade = player.nade;
        if (held_nade)
@@ -1278,7 +1293,10 @@ MUTATOR_HOOKFUNCTION(nades, PlayerPreThink)
                held_nade.angles_y = player.angles.y;
 
                if (time + 0.1 >= held_nade.wait)
+               {
                        toss_nade(player, false, '0 0 0', time + 0.05);
+                       Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_NADE_THROW);
+               }
        }
 
        if(IS_PLAYER(player))
@@ -1330,43 +1348,43 @@ MUTATOR_HOOKFUNCTION(nades, PlayerPreThink)
        }
 
        int n = 0;
-       entity o = NULL;
+
+       IntrusiveList reviving_players = NULL;
+
        if(player.freezetag_frozen_timeout > 0 && time >= player.freezetag_frozen_timeout)
                n = -1;
-       else if(STAT(FROZEN, player) == 3)
+       else if (STAT(FROZEN, player) == FROZEN_TEMP_DYING)
        {
                vector revive_extra_size = '1 1 1' * autocvar_g_freezetag_revive_extra_size;
                n = 0;
-               FOREACH_CLIENT(IS_PLAYER(it) && it != player, {
-                       if(!IS_DEAD(it) && STAT(FROZEN, it) == 0 && SAME_TEAM(it, player))
-                       if(boxesoverlap(player.absmin - revive_extra_size, player.absmax + revive_extra_size, it.absmin, it.absmax))
-                       {
-                               if(!o)
-                                       o = it;
-                               it.reviving = true;
-                               ++n;
-                       }
+               FOREACH_CLIENT(IS_PLAYER(it) && IS_REVIVING(player, it, revive_extra_size), {
+                       if (!reviving_players)
+                               reviving_players = IL_NEW();
+                       IL_PUSH(reviving_players, it);
+                       ++n;
                });
        }
 
-       if(n > 0 && STAT(FROZEN, player) == 3) // OK, there is at least one teammate reviving us
+       if (n > 0 && STAT(FROZEN, player) == FROZEN_TEMP_DYING) // OK, there is at least one teammate reviving us
        {
                STAT(REVIVE_PROGRESS, player) = bound(0, STAT(REVIVE_PROGRESS, player) + frametime * max(1/60, autocvar_g_freezetag_revive_speed), 1);
-               SetResourceAmount(player, RESOURCE_HEALTH, max(1, STAT(REVIVE_PROGRESS, player) * start_health));
+               SetResource(player, RES_HEALTH, max(1, STAT(REVIVE_PROGRESS, player) * start_health));
 
                if(STAT(REVIVE_PROGRESS, player) >= 1)
                {
-                       Unfreeze(player);
+                       Unfreeze(player, false);
 
-                       Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_FREEZETAG_REVIVED, o.netname);
-                       Send_Notification(NOTIF_ONE, o, MSG_CENTER, CENTER_FREEZETAG_REVIVE, player.netname);
+                       entity first = IL_FIRST(reviving_players);
+                       Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_FREEZETAG_REVIVED, first.netname);
+                       Send_Notification(NOTIF_ONE, first, MSG_CENTER, CENTER_FREEZETAG_REVIVE, player.netname);
                }
 
-               FOREACH_CLIENT(IS_PLAYER(it) && it.reviving, {
+               IL_EACH(reviving_players, true, {
                        STAT(REVIVE_PROGRESS, it) = STAT(REVIVE_PROGRESS, player);
-                       it.reviving = false;
                });
        }
+       if (reviving_players)
+               IL_DELETE(reviving_players);
 }
 
 MUTATOR_HOOKFUNCTION(nades, PlayerPhysics_UpdateStats)
@@ -1435,8 +1453,8 @@ MUTATOR_HOOKFUNCTION(nades, PlayerDies, CBC_ORDER_LAST)
 
        if(IS_PLAYER(frag_attacker))
        {
-               float killcount_bonus = ((CS(frag_attacker).killcount >= 1) ? bound(0, autocvar_g_nades_bonus_score_minor * CS(frag_attacker).killcount, autocvar_g_nades_bonus_score_medium) : autocvar_g_nades_bonus_score_minor);
-
+               float killcount_bonus = ((CS(frag_attacker).killcount >= 1) ? bound(0, autocvar_g_nades_bonus_score_minor * CS(frag_attacker).killcount, autocvar_g_nades_bonus_score_medium) 
+                                                                                                                                       : autocvar_g_nades_bonus_score_minor);
                if (SAME_TEAM(frag_attacker, frag_target) || frag_attacker == frag_target)
                        nades_RemoveBonus(frag_attacker);
                else if(GameRules_scoring_is_vip(frag_target))
@@ -1469,8 +1487,8 @@ MUTATOR_HOOKFUNCTION(nades, Damage_Calculate)
        if(autocvar_g_freezetag_revive_nade && STAT(FROZEN, frag_target) && frag_attacker == frag_target && frag_deathtype == DEATH_NADE.m_id)
        if(time - frag_inflictor.toss_time <= 0.1)
        {
-               Unfreeze(frag_target);
-               SetResourceAmount(frag_target, RESOURCE_HEALTH, autocvar_g_freezetag_revive_nade_health);
+               Unfreeze(frag_target, false);
+               SetResource(frag_target, RES_HEALTH, autocvar_g_freezetag_revive_nade_health);
                Send_Effect(EFFECT_ICEORGLASS, frag_target.origin, '0 0 0', 3);
                M_ARGV(4, float) = 0;
                M_ARGV(6, vector) = '0 0 0';
@@ -1532,9 +1550,6 @@ MUTATOR_HOOKFUNCTION(nades, SpectateCopy)
        STAT(VEIL_ORB_ALPHA, client) = STAT(VEIL_ORB_ALPHA, spectatee);
 }
 
-REPLICATE(cvar_cl_nade_type, int, "cl_nade_type");
-REPLICATE(cvar_cl_pokenade_type, string, "cl_pokenade_type");
-
 MUTATOR_HOOKFUNCTION(nades, BuildMutatorsString)
 {
        M_ARGV(0, string) = strcat(M_ARGV(0, string), ":Nades");
@@ -1542,7 +1557,7 @@ MUTATOR_HOOKFUNCTION(nades, BuildMutatorsString)
 
 MUTATOR_HOOKFUNCTION(nades, BuildGameplayTipsString)
 {
-       M_ARGV(0, string) = strcat(M_ARGV(0, string), "\n\n^3nades^8 are enabled, press 'g' to use them\n");
+       M_ARGV(0, string) = strcat(M_ARGV(0, string), "\n\n^3nades^8 are enabled, press 'g' (dropweapon) to use them\n");
 }
 
 #endif