]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/common/t_items.qc
Merge branch 'master' into Mario/stats_eloranking
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / t_items.qc
index dfee5330df713431f4afba5cc9be713504171323..a5786888c18169abdfb93a44200b9383feab5a8d 100644 (file)
@@ -356,8 +356,8 @@ bool ItemSend(entity this, entity to, int sf)
        {
                WriteShort(MSG_ENTITY, this.colormap);
                WriteByte(MSG_ENTITY, this.glowmod.x * 255.0);
-        WriteByte(MSG_ENTITY, this.glowmod.y * 255.0);
-        WriteByte(MSG_ENTITY, this.glowmod.z * 255.0);
+               WriteByte(MSG_ENTITY, this.glowmod.y * 255.0);
+               WriteByte(MSG_ENTITY, this.glowmod.z * 255.0);
        }
 
        if(sf & ISF_DROP)
@@ -402,7 +402,7 @@ bool have_pickup_item(entity this)
        return true;
 }
 
-void Item_Show (entity e, int mode)
+void Item_Show(entity e, int mode)
 {
        e.effects &= ~(EF_ADDITIVE | EF_STARDUST | EF_FULLBRIGHT | EF_NODEPTHTEST);
        e.ItemStatus &= ~ITS_STAYWEP;
@@ -479,13 +479,13 @@ float Item_ItemsTime_UpdateTime(entity e, float t);
 void Item_ItemsTime_SetTime(entity e, float t);
 void Item_ItemsTime_SetTimesForAllPlayers();
 
-void Item_Respawn (entity this)
+void Item_Respawn(entity this)
 {
        Item_Show(this, 1);
        sound(this, CH_TRIGGER, this.itemdef.m_respawnsound, VOL_BASE, ATTEN_NORM);     // play respawn sound
        setorigin(this, this.origin);
 
-    if (Item_ItemsTime_Allow(this.itemdef) || (STAT(WEAPONS, this) & WEPSET_SUPERWEAPONS))
+       if (Item_ItemsTime_Allow(this.itemdef) || (STAT(WEAPONS, this) & WEPSET_SUPERWEAPONS))
        {
                float t = Item_ItemsTime_UpdateTime(this, 0);
                Item_ItemsTime_SetTime(this, t);
@@ -499,7 +499,7 @@ void Item_Respawn (entity this)
        Send_Effect(EFFECT_ITEM_RESPAWN, CENTER_OR_VIEWOFS(this), '0 0 0', 1);
 }
 
-void Item_RespawnCountdown (entity this)
+void Item_RespawnCountdown(entity this)
 {
        if(this.item_respawncounter >= ITEM_RESPAWN_TICKS)
        {
@@ -624,7 +624,7 @@ float adjust_respawntime(float normal_respawntime) {
                }
        }
        TeamBalance_Destroy(balance);
-       
+
        if (players >= 2) {
                return normal_respawntime * (r / (players + o) + l);
        } else {
@@ -717,52 +717,48 @@ void GiveRandomWeapons(entity receiver, int num_weapons, string weapon_names,
                        return;
                }
                STAT(WEAPONS, receiver) |= RandomSelection_chosen_ent.m_wepset;
-               if (RandomSelection_chosen_ent.ammo_type == RESOURCE_NONE)
+               if (RandomSelection_chosen_ent.ammo_type == RES_NONE)
                {
                        continue;
                }
-               if (GetResourceAmount(receiver,
+               if (GetResource(receiver,
                        RandomSelection_chosen_ent.ammo_type) != 0)
                {
                        continue;
                }
                GiveResource(receiver, RandomSelection_chosen_ent.ammo_type,
-                       GetResourceAmount(ammo_entity,
+                       GetResource(ammo_entity,
                        RandomSelection_chosen_ent.ammo_type));
        }
 }
 
-float Item_GiveAmmoTo(entity item, entity player, int resource_type, float ammomax)
+bool Item_GiveAmmoTo(entity item, entity player, int res_type, float ammomax)
 {
-       float amount = GetResourceAmount(item, resource_type);
+       float amount = GetResource(item, res_type);
        if (amount == 0)
        {
                return false;
        }
-       float player_amount = GetResourceAmount(player, resource_type);
+       float player_amount = GetResource(player, res_type);
        if (item.spawnshieldtime)
        {
                if ((player_amount >= ammomax) && (item.pickup_anyway <= 0))
-               {
                        return false;
-               }
-               GiveOrTakeResourceWithLimit(player, resource_type, amount, ammomax);
-               return true;
        }
-       if (g_weapon_stay != 2)
-       {
+       else if (g_weapon_stay == 2)
+               ammomax = min(amount, ammomax);
+       else
                return false;
-       }
-       GiveOrTakeResourceWithLimit(player, resource_type, amount, min(amount, ammomax));
+       if (amount < 0)
+               TakeResourceWithLimit(player, res_type, -amount, ammomax);
+       else
+               GiveResourceWithLimit(player, res_type, amount, ammomax);
        return true;
 }
 
-float Item_GiveTo(entity item, entity player)
+bool Item_GiveTo(entity item, entity player)
 {
-       float pickedup;
-
        // if nothing happens to player, just return without taking the item
-       pickedup = false;
        int _switchweapon = 0;
        // in case the player has autoswitch enabled do the following:
        // if the player is using their best weapon before items are given, they
@@ -783,14 +779,15 @@ float Item_GiveTo(entity item, entity player)
                        }
                }
        }
-       pickedup |= Item_GiveAmmoTo(item, player, RESOURCE_HEALTH, item.max_health);
-       pickedup |= Item_GiveAmmoTo(item, player, RESOURCE_ARMOR, item.max_armorvalue);
-       pickedup |= Item_GiveAmmoTo(item, player, RESOURCE_SHELLS, g_pickup_shells_max);
-       pickedup |= Item_GiveAmmoTo(item, player, RESOURCE_BULLETS, g_pickup_nails_max);
-       pickedup |= Item_GiveAmmoTo(item, player, RESOURCE_ROCKETS, g_pickup_rockets_max);
-       pickedup |= Item_GiveAmmoTo(item, player, RESOURCE_CELLS, g_pickup_cells_max);
-       pickedup |= Item_GiveAmmoTo(item, player, RESOURCE_PLASMA, g_pickup_plasma_max);
-       pickedup |= Item_GiveAmmoTo(item, player, RESOURCE_FUEL, g_pickup_fuel_max);
+       bool pickedup = false;
+       pickedup = (pickedup || Item_GiveAmmoTo(item, player, RES_HEALTH, item.max_health));
+       pickedup = (pickedup || Item_GiveAmmoTo(item, player, RES_ARMOR, item.max_armorvalue));
+       pickedup = (pickedup || Item_GiveAmmoTo(item, player, RES_SHELLS, g_pickup_shells_max));
+       pickedup = (pickedup || Item_GiveAmmoTo(item, player, RES_BULLETS, g_pickup_nails_max));
+       pickedup = (pickedup || Item_GiveAmmoTo(item, player, RES_ROCKETS, g_pickup_rockets_max));
+       pickedup = (pickedup || Item_GiveAmmoTo(item, player, RES_CELLS, g_pickup_cells_max));
+       pickedup = (pickedup || Item_GiveAmmoTo(item, player, RES_PLASMA, g_pickup_plasma_max));
+       pickedup = (pickedup || Item_GiveAmmoTo(item, player, RES_FUEL, g_pickup_fuel_max));
        if (item.itemdef.instanceOfWeaponPickup)
        {
                WepSet w;
@@ -853,7 +850,7 @@ float Item_GiveTo(entity item, entity player)
                pickedup = true;
 
        if (!pickedup)
-               return 0;
+               return false;
 
        // crude hack to enforce switching weapons
        if(g_cts && item.itemdef.instanceOfWeaponPickup && !CS(player).cvar_cl_cts_noautoswitch)
@@ -864,7 +861,7 @@ float Item_GiveTo(entity item, entity player)
                        if(player.(weaponentity).m_weapon != WEP_Null || slot == 0)
                                W_SwitchWeapon_Force(player, Weapons_from(item.weapon), weaponentity);
                }
-               return 1;
+               return true;
        }
 
        if(_switchweapon)
@@ -878,7 +875,7 @@ float Item_GiveTo(entity item, entity player)
                }
        }
 
-       return 1;
+       return true;
 }
 
 void Item_Touch(entity this, entity toucher)
@@ -930,6 +927,9 @@ void Item_Touch(entity this, entity toucher)
 
 LABEL(pickup)
 
+       if(this.target && this.target != "" && this.target != "###item###") // defrag support
+               SUB_UseTargets(this, toucher, NULL);
+
        STAT(LAST_PICKUP, toucher) = time;
 
        Send_Effect(EFFECT_ITEM_PICKUP, CENTER_OR_VIEWOFS(this), '0 0 0', 1);
@@ -1008,8 +1008,8 @@ void Item_FindTeam(entity this)
                });
 
                e = RandomSelection_chosen_ent;
-               e.state = 0;
-               Item_Show(e, 1);
+               if (!e)
+                       return;
 
                IL_EACH(g_items, it.team == this.team,
                {
@@ -1021,11 +1021,11 @@ void Item_FindTeam(entity this)
                                        Item_Show(it, -1);
                                        it.state = 1; // state 1 = initially hidden item, apparently
                                }
+                               else
+                                       Item_Reset(it);
                                it.effects &= ~EF_NODRAW;
                        }
                });
-
-               Item_Reset(this);
        }
 }
 
@@ -1075,12 +1075,12 @@ float ammo_pickupevalfunc(entity player, entity item)
        if(item.itemdef.instanceOfWeaponPickup)
        {
                entity ammo = NULL;
-               if(GetResourceAmount(item, RESOURCE_SHELLS))       { need_shells  = true; ammo = ITEM_Shells;      }
-               else if(GetResourceAmount(item, RESOURCE_BULLETS))   { need_nails   = true; ammo = ITEM_Bullets;     }
-               else if(GetResourceAmount(item, RESOURCE_ROCKETS)) { need_rockets = true; ammo = ITEM_Rockets;     }
-               else if(GetResourceAmount(item, RESOURCE_CELLS))   { need_cells   = true; ammo = ITEM_Cells;       }
-               else if(GetResourceAmount(item, RESOURCE_PLASMA))  { need_plasma  = true; ammo = ITEM_Plasma;      }
-               else if(GetResourceAmount(item, RESOURCE_FUEL))    { need_fuel    = true; ammo = ITEM_JetpackFuel; }
+               if(GetResource(item, RES_SHELLS))       { need_shells  = true; ammo = ITEM_Shells;      }
+               else if(GetResource(item, RES_BULLETS))   { need_nails   = true; ammo = ITEM_Bullets;     }
+               else if(GetResource(item, RES_ROCKETS)) { need_rockets = true; ammo = ITEM_Rockets;     }
+               else if(GetResource(item, RES_CELLS))   { need_cells   = true; ammo = ITEM_Cells;       }
+               else if(GetResource(item, RES_PLASMA))  { need_plasma  = true; ammo = ITEM_Plasma;      }
+               else if(GetResource(item, RES_FUEL))    { need_fuel    = true; ammo = ITEM_JetpackFuel; }
 
                if(!ammo)
                        return 0;
@@ -1095,12 +1095,12 @@ float ammo_pickupevalfunc(entity player, entity item)
 
                        switch(it.ammo_type)
                        {
-                               case RESOURCE_SHELLS:  need_shells  = true; break;
-                               case RESOURCE_BULLETS: need_nails   = true; break;
-                               case RESOURCE_ROCKETS: need_rockets = true; break;
-                               case RESOURCE_CELLS:   need_cells   = true; break;
-                               case RESOURCE_PLASMA:  need_plasma  = true; break;
-                               case RESOURCE_FUEL:    need_fuel    = true; break;
+                               case RES_SHELLS:  need_shells  = true; break;
+                               case RES_BULLETS: need_nails   = true; break;
+                               case RES_ROCKETS: need_rockets = true; break;
+                               case RES_CELLS:   need_cells   = true; break;
+                               case RES_PLASMA:  need_plasma  = true; break;
+                               case RES_FUEL:    need_fuel    = true; break;
                        }
                });
                rating = item.bot_pickupbasevalue;
@@ -1108,23 +1108,23 @@ float ammo_pickupevalfunc(entity player, entity item)
 
        float noammorating = 0.5;
 
-       if ((need_shells) && GetResourceAmount(item, RESOURCE_SHELLS) && (GetResourceAmount(player, RESOURCE_SHELLS) < g_pickup_shells_max))
-               c = GetResourceAmount(item, RESOURCE_SHELLS) / max(noammorating, GetResourceAmount(player, RESOURCE_SHELLS));
+       if ((need_shells) && GetResource(item, RES_SHELLS) && (GetResource(player, RES_SHELLS) < g_pickup_shells_max))
+               c = GetResource(item, RES_SHELLS) / max(noammorating, GetResource(player, RES_SHELLS));
 
-       if ((need_nails) && GetResourceAmount(item, RESOURCE_BULLETS) && (GetResourceAmount(player, RESOURCE_BULLETS) < g_pickup_nails_max))
-               c = GetResourceAmount(item, RESOURCE_BULLETS) / max(noammorating, GetResourceAmount(player, RESOURCE_BULLETS));
+       if ((need_nails) && GetResource(item, RES_BULLETS) && (GetResource(player, RES_BULLETS) < g_pickup_nails_max))
+               c = GetResource(item, RES_BULLETS) / max(noammorating, GetResource(player, RES_BULLETS));
 
-       if ((need_rockets) && GetResourceAmount(item, RESOURCE_ROCKETS) && (GetResourceAmount(player, RESOURCE_ROCKETS) < g_pickup_rockets_max))
-               c = GetResourceAmount(item, RESOURCE_ROCKETS) / max(noammorating, GetResourceAmount(player, RESOURCE_ROCKETS));
+       if ((need_rockets) && GetResource(item, RES_ROCKETS) && (GetResource(player, RES_ROCKETS) < g_pickup_rockets_max))
+               c = GetResource(item, RES_ROCKETS) / max(noammorating, GetResource(player, RES_ROCKETS));
 
-       if ((need_cells) && GetResourceAmount(item, RESOURCE_CELLS) && (GetResourceAmount(player, RESOURCE_CELLS) < g_pickup_cells_max))
-               c = GetResourceAmount(item, RESOURCE_CELLS) / max(noammorating, GetResourceAmount(player, RESOURCE_CELLS));
+       if ((need_cells) && GetResource(item, RES_CELLS) && (GetResource(player, RES_CELLS) < g_pickup_cells_max))
+               c = GetResource(item, RES_CELLS) / max(noammorating, GetResource(player, RES_CELLS));
 
-       if ((need_plasma) && GetResourceAmount(item, RESOURCE_PLASMA) && (GetResourceAmount(player, RESOURCE_PLASMA) < g_pickup_plasma_max))
-               c = GetResourceAmount(item, RESOURCE_PLASMA) / max(noammorating, GetResourceAmount(player, RESOURCE_PLASMA));
+       if ((need_plasma) && GetResource(item, RES_PLASMA) && (GetResource(player, RES_PLASMA) < g_pickup_plasma_max))
+               c = GetResource(item, RES_PLASMA) / max(noammorating, GetResource(player, RES_PLASMA));
 
-       if ((need_fuel) && GetResourceAmount(item, RESOURCE_FUEL) && (GetResourceAmount(player, RESOURCE_FUEL) < g_pickup_fuel_max))
-               c = GetResourceAmount(item, RESOURCE_FUEL) / max(noammorating, GetResourceAmount(player, RESOURCE_FUEL));
+       if ((need_fuel) && GetResource(item, RES_FUEL) && (GetResource(player, RES_FUEL) < g_pickup_fuel_max))
+               c = GetResource(item, RES_FUEL) / max(noammorating, GetResource(player, RES_FUEL));
 
        rating *= min(c, 2);
        if(wpn)
@@ -1137,8 +1137,8 @@ float healtharmor_pickupevalfunc(entity player, entity item)
        float c = 0;
        float rating = item.bot_pickupbasevalue;
 
-       float itemarmor = GetResourceAmount(item, RESOURCE_ARMOR);
-       float itemhealth = GetResourceAmount(item, RESOURCE_HEALTH);
+       float itemarmor = GetResource(item, RES_ARMOR);
+       float itemhealth = GetResource(item, RES_HEALTH);
 
        if(item.item_group)
        {
@@ -1146,11 +1146,11 @@ float healtharmor_pickupevalfunc(entity player, entity item)
                itemhealth *= min(4, item.item_group_count);
        }
 
-       if (itemarmor && (GetResourceAmount(player, RESOURCE_ARMOR) < item.max_armorvalue))
-               c = itemarmor / max(1, GetResourceAmount(player, RESOURCE_ARMOR) * 2/3 + GetResourceAmount(player, RESOURCE_HEALTH) * 1/3);
+       if (itemarmor && (GetResource(player, RES_ARMOR) < item.max_armorvalue))
+               c = itemarmor / max(1, GetResource(player, RES_ARMOR) * 2/3 + GetResource(player, RES_HEALTH) * 1/3);
 
-       if (itemhealth && (GetResourceAmount(player, RESOURCE_HEALTH) < item.max_health))
-               c = itemhealth / max(1, GetResourceAmount(player, RESOURCE_HEALTH));
+       if (itemhealth && (GetResource(player, RES_HEALTH) < item.max_health))
+               c = itemhealth / max(1, GetResource(player, RES_HEALTH));
 
        rating *= min(2, c);
        return rating;
@@ -1172,7 +1172,7 @@ void _StartItem(entity this, entity def, float defaultrespawntime, float default
 {
        string itemname = def.m_name;
        Model itemmodel = def.m_model;
-    Sound pickupsound = def.m_sound;
+       Sound pickupsound = def.m_sound;
        float(entity player, entity item) pickupevalfunc = def.m_pickupevalfunc;
        float pickupbasevalue = def.m_botvalue;
        int itemflags = def.m_itemflags;
@@ -1180,10 +1180,10 @@ void _StartItem(entity this, entity def, float defaultrespawntime, float default
        startitem_failed = false;
 
        this.item_model_ent = itemmodel;
-    this.item_pickupsound_ent = pickupsound;
+       this.item_pickupsound_ent = pickupsound;
 
-    if(def.m_iteminit)
-       def.m_iteminit(def, this);
+       if(def.m_iteminit)
+               def.m_iteminit(def, this);
 
        if(!this.respawntime) // both need to be set
        {
@@ -1218,6 +1218,9 @@ void _StartItem(entity this, entity def, float defaultrespawntime, float default
                return;
        }
 
+       precache_model(this.model);
+       precache_sound(this.item_pickupsound);
+
        if (Item_IsLoot(this))
        {
                this.reset = SUB_Remove;
@@ -1309,15 +1312,16 @@ void _StartItem(entity this, entity def, float defaultrespawntime, float default
 
                weaponsInMap |= WepSet_FromWeapon(Weapons_from(weaponid));
 
-               precache_model(this.model);
-               precache_sound(this.item_pickupsound);
-
                if (   def.instanceOfPowerup
                        || def.instanceOfWeaponPickup
                        || (def.instanceOfHealth && def != ITEM_HealthSmall)
                        || (def.instanceOfArmor && def != ITEM_ArmorSmall)
                        || (itemid & (IT_KEY1 | IT_KEY2))
-               ) this.target = "###item###"; // for finding the nearest item using findnearest
+               )
+               {
+                       if(!this.target || this.target == "")
+                               this.target = "###item###"; // for finding the nearest item using findnearest
+               }
 
                Item_ItemsTime_SetTime(this, 0);
        }
@@ -1339,23 +1343,24 @@ void _StartItem(entity this, entity def, float defaultrespawntime, float default
                if(def.instanceOfPowerup)
                        this.ItemStatus |= ITS_ANIMATE1;
 
-               if(GetResourceAmount(this, RESOURCE_ARMOR) || GetResourceAmount(this, RESOURCE_HEALTH))
+               if(GetResource(this, RES_ARMOR) || GetResource(this, RES_HEALTH))
                        this.ItemStatus |= ITS_ANIMATE2;
        }
 
+       if(Item_IsLoot(this))
+               this.gravity = 1;
+
        if(def.instanceOfWeaponPickup)
        {
                if (!Item_IsLoot(this)) // if dropped, colormap is already set up nicely
                        this.colormap = 1024; // color shirt=0 pants=0 grey
-               else
-                       this.gravity = 1;
                if (!(this.spawnflags & 1024))
                        this.ItemStatus |= ITS_ANIMATE1;
                this.SendFlags |= ISF_COLORMAP;
        }
 
        this.state = 0;
-       if(this.team) // broken, no idea why.
+       if(this.team)
        {
                if(!this.cnt)
                        this.cnt = 1; // item probability weight
@@ -1401,7 +1406,7 @@ int group_count = 1;
 
 void setItemGroup(entity this)
 {
-       if(!IS_SMALL(this.itemdef))
+       if(!IS_SMALL(this.itemdef) || Item_IsLoot(this))
                return;
 
        FOREACH_ENTITY_RADIUS(this.origin, 120, (it != this) && IS_SMALL(it.itemdef),
@@ -1505,9 +1510,11 @@ spawnfunc(target_items)
                                FOREACH(Buffs, it != BUFF_Null,
                                {
                                        s = Buff_UndeprecateName(argv(j));
-                                       if(s == it.m_name)
+                                       if(s == it.netname)
                                        {
                                                STAT(BUFFS, this) |= (it.m_itemid);
+                                               if(!STAT(BUFF_TIME, this))
+                                                       STAT(BUFF_TIME, this) = it.m_time(it);
                                                break;
                                        }
                                });
@@ -1559,15 +1566,15 @@ spawnfunc(target_items)
                this.netname = sprintf("%s %s%d %s", this.netname, valueprefix, this.superweapons_finished * boolean(this.items & IT_SUPERWEAPON), "superweapons");
                this.netname = sprintf("%s %s%d %s", this.netname, itemprefix, boolean(this.items & ITEM_Jetpack.m_itemid), "jetpack");
                this.netname = sprintf("%s %s%d %s", this.netname, itemprefix, boolean(this.items & ITEM_JetpackRegen.m_itemid), "fuel_regen");
-               if(GetResourceAmount(this, RESOURCE_SHELLS) != 0) this.netname = sprintf("%s %s%d %s", this.netname, valueprefix, max(0, GetResourceAmount(this, RESOURCE_SHELLS)), "shells");
-               if(GetResourceAmount(this, RESOURCE_BULLETS) != 0) this.netname = sprintf("%s %s%d %s", this.netname, valueprefix, max(0, GetResourceAmount(this, RESOURCE_BULLETS)), "nails");
-               if(GetResourceAmount(this, RESOURCE_ROCKETS) != 0) this.netname = sprintf("%s %s%d %s", this.netname, valueprefix, max(0, GetResourceAmount(this, RESOURCE_ROCKETS)), "rockets");
-               if(GetResourceAmount(this, RESOURCE_CELLS) != 0) this.netname = sprintf("%s %s%d %s", this.netname, valueprefix, max(0, GetResourceAmount(this, RESOURCE_CELLS)), "cells");
-               if(GetResourceAmount(this, RESOURCE_PLASMA) != 0) this.netname = sprintf("%s %s%d %s", this.netname, valueprefix, max(0, GetResourceAmount(this, RESOURCE_PLASMA)), "plasma");
-               if(GetResourceAmount(this, RESOURCE_FUEL) != 0) this.netname = sprintf("%s %s%d %s", this.netname, valueprefix, max(0, GetResourceAmount(this, RESOURCE_FUEL)), "fuel");
-               if(GetResourceAmount(this, RESOURCE_HEALTH) != 0) this.netname = sprintf("%s %s%d %s", this.netname, valueprefix, max(0, GetResourceAmount(this, RESOURCE_HEALTH)), "health");
-               if(GetResourceAmount(this, RESOURCE_ARMOR) != 0) this.netname = sprintf("%s %s%d %s", this.netname, valueprefix, max(0, GetResourceAmount(this, RESOURCE_ARMOR)), "armor");
-               FOREACH(Buffs, it != BUFF_Null, this.netname = sprintf("%s %s%d %s", this.netname, itemprefix, !!(STAT(BUFFS, this) & (it.m_itemid)), it.m_name));
+               if(GetResource(this, RES_SHELLS) != 0) this.netname = sprintf("%s %s%d %s", this.netname, valueprefix, max(0, GetResource(this, RES_SHELLS)), "shells");
+               if(GetResource(this, RES_BULLETS) != 0) this.netname = sprintf("%s %s%d %s", this.netname, valueprefix, max(0, GetResource(this, RES_BULLETS)), "nails");
+               if(GetResource(this, RES_ROCKETS) != 0) this.netname = sprintf("%s %s%d %s", this.netname, valueprefix, max(0, GetResource(this, RES_ROCKETS)), "rockets");
+               if(GetResource(this, RES_CELLS) != 0) this.netname = sprintf("%s %s%d %s", this.netname, valueprefix, max(0, GetResource(this, RES_CELLS)), "cells");
+               if(GetResource(this, RES_PLASMA) != 0) this.netname = sprintf("%s %s%d %s", this.netname, valueprefix, max(0, GetResource(this, RES_PLASMA)), "plasma");
+               if(GetResource(this, RES_FUEL) != 0) this.netname = sprintf("%s %s%d %s", this.netname, valueprefix, max(0, GetResource(this, RES_FUEL)), "fuel");
+               if(GetResource(this, RES_HEALTH) != 0) this.netname = sprintf("%s %s%d %s", this.netname, valueprefix, max(0, GetResource(this, RES_HEALTH)), "health");
+               if(GetResource(this, RES_ARMOR) != 0) this.netname = sprintf("%s %s%d %s", this.netname, valueprefix, max(0, GetResource(this, RES_ARMOR)), "armor");
+               FOREACH(Buffs, it != BUFF_Null && (STAT(BUFFS, this) & it.m_itemid), this.netname = sprintf("%s %s%d %s", this.netname, valueprefix, max(0, STAT(BUFF_TIME, this)), it.netname));
                FOREACH(Weapons, it != WEP_Null, this.netname = sprintf("%s %s%d %s", this.netname, itemprefix, !!(STAT(WEAPONS, this) & (it.m_wepset)), it.netname));
        }
        this.netname = strzone(this.netname);
@@ -1577,8 +1584,8 @@ spawnfunc(target_items)
        for(int j = 0; j < n; ++j)
        {
                FOREACH(Weapons, it != WEP_Null && W_UndeprecateName(argv(j)) == it.netname, {
-            it.wr_init(it);
-            break;
+                       it.wr_init(it);
+                       break;
                });
        }
 }
@@ -1617,28 +1624,28 @@ float GiveWeapon(entity e, float wpn, float op, float val)
 bool GiveBuff(entity e, Buff thebuff, int op, int val)
 {
        bool had_buff = (STAT(BUFFS, e) & thebuff.m_itemid);
-       switch(op)
+       switch (op)
        {
                case OP_SET:
-                       if(val > 0)
-                               STAT(BUFFS, e) |= thebuff.m_itemid;
-                       else
-                               STAT(BUFFS, e) &= ~thebuff.m_itemid;
+                       STAT(BUFF_TIME, e) = val;
                        break;
                case OP_MIN:
-               case OP_PLUS:
-                       if(val > 0)
-                               STAT(BUFFS, e) |= thebuff.m_itemid;
+                       STAT(BUFF_TIME, e) = max(STAT(BUFF_TIME, e), val);
                        break;
                case OP_MAX:
-                       if(val <= 0)
-                               STAT(BUFFS, e) &= ~thebuff.m_itemid;
+                       STAT(BUFF_TIME, e) = min(STAT(BUFF_TIME, e), val);
+                       break;
+               case OP_PLUS:
+                       STAT(BUFF_TIME, e) += val;
                        break;
                case OP_MINUS:
-                       if(val > 0)
-                               STAT(BUFFS, e) &= ~thebuff.m_itemid;
+                       STAT(BUFF_TIME, e) -= val;
                        break;
        }
+       if(STAT(BUFF_TIME, e) <= 0)
+               STAT(BUFFS, e) &= ~thebuff.m_itemid;
+       else
+               STAT(BUFFS, e) = thebuff.m_itemid; // NOTE: replaces any existing buffs on the player!
        bool have_buff = (STAT(BUFFS, e) & thebuff.m_itemid);
        return (had_buff != have_buff);
 }
@@ -1666,28 +1673,19 @@ void GiveRot(entity e, float v0, float v1, .float rotfield, float rottime, .floa
        else if(v0 > v1)
                e.(regenfield) = max(e.(regenfield), time + regentime);
 }
-bool GiveResourceValue(entity e, int resource_type, int op, int val)
+bool GiveResourceValue(entity e, int res_type, int op, int val)
 {
-       int v0 = GetResourceAmount(e, resource_type);
+       int v0 = GetResource(e, res_type);
        switch (op)
        {
-               case OP_SET:
-                       SetResourceAmount(e, resource_type, val);
-                       break;
-               case OP_MIN:
-                       SetResourceAmount(e, resource_type, max(v0, val)); // min 100 cells = at least 100 cells
-                       break;
-               case OP_MAX:
-                       SetResourceAmount(e, resource_type, min(v0, val));
-                       break;
-               case OP_PLUS:
-                       SetResourceAmount(e, resource_type, v0 + val);
-                       break;
-               case OP_MINUS:
-                       SetResourceAmount(e, resource_type, v0 - val);
-                       break;
+               // min 100 cells = at least 100 cells
+               case OP_SET: SetResource(e, res_type, val); break;
+               case OP_MIN: SetResource(e, res_type, max(v0, val)); break;
+               case OP_MAX: SetResource(e, res_type, min(v0, val)); break;
+               case OP_PLUS: SetResource(e, res_type, v0 + val); break;
+               case OP_MINUS: SetResource(e, res_type, v0 - val); break;
        }
-       int v1 = GetResourceAmount(e, resource_type);
+       int v1 = GetResource(e, res_type);
        return v0 != v1;
 }
 
@@ -1717,20 +1715,21 @@ float GiveItems(entity e, float beginarg, float endarg)
        e.strength_finished = max(0, e.strength_finished - time);
        e.invincible_finished = max(0, e.invincible_finished - time);
        e.superweapons_finished = max(0, e.superweapons_finished - time);
+       STAT(BUFF_TIME, e) = max(0, STAT(BUFF_TIME, e) - time);
 
        PREGIVE(e, items);
        PREGIVE_WEAPONS(e);
        PREGIVE(e, strength_finished);
        PREGIVE(e, invincible_finished);
        PREGIVE(e, superweapons_finished);
-       PREGIVE_RESOURCE(e, RESOURCE_BULLETS);
-       PREGIVE_RESOURCE(e, RESOURCE_CELLS);
-       PREGIVE_RESOURCE(e, RESOURCE_PLASMA);
-       PREGIVE_RESOURCE(e, RESOURCE_SHELLS);
-       PREGIVE_RESOURCE(e, RESOURCE_ROCKETS);
-       PREGIVE_RESOURCE(e, RESOURCE_FUEL);
-       PREGIVE_RESOURCE(e, RESOURCE_ARMOR);
-       PREGIVE_RESOURCE(e, RESOURCE_HEALTH);
+       PREGIVE_RESOURCE(e, RES_BULLETS);
+       PREGIVE_RESOURCE(e, RES_CELLS);
+       PREGIVE_RESOURCE(e, RES_PLASMA);
+       PREGIVE_RESOURCE(e, RES_SHELLS);
+       PREGIVE_RESOURCE(e, RES_ROCKETS);
+       PREGIVE_RESOURCE(e, RES_FUEL);
+       PREGIVE_RESOURCE(e, RES_ARMOR);
+       PREGIVE_RESOURCE(e, RES_HEALTH);
 
        for(i = beginarg; i < endarg; ++i)
        {
@@ -1767,19 +1766,19 @@ float GiveItems(entity e, float beginarg, float endarg)
                                got += GiveBit(e, items, IT_UNLIMITED_AMMO, op, val);
                        case "all":
                                got += GiveBit(e, items, ITEM_Jetpack.m_itemid, op, val);
-                               got += GiveResourceValue(e, RESOURCE_HEALTH, op, val);
-                               got += GiveResourceValue(e, RESOURCE_ARMOR, op, val);
+                               got += GiveResourceValue(e, RES_HEALTH, op, val);
+                               got += GiveResourceValue(e, RES_ARMOR, op, val);
                        case "allweapons":
-                               FOREACH(Weapons, it != WEP_Null && !(it.spawnflags & WEP_FLAG_MUTATORBLOCKED), got += GiveWeapon(e, it.m_id, op, val));
+                               FOREACH(Weapons, it != WEP_Null && !(it.spawnflags & (WEP_FLAG_MUTATORBLOCKED | WEP_FLAG_SPECIALATTACK)), got += GiveWeapon(e, it.m_id, op, val));
                        //case "allbuffs": // all buffs makes a player god, do not want!
                                //FOREACH(Buffs, it != BUFF_Null, got += GiveBuff(e, it.m_itemid, op, val));
                        case "allammo":
-                               got += GiveResourceValue(e, RESOURCE_CELLS, op, val);
-                               got += GiveResourceValue(e, RESOURCE_PLASMA, op, val);
-                               got += GiveResourceValue(e, RESOURCE_SHELLS, op, val);
-                               got += GiveResourceValue(e, RESOURCE_BULLETS, op, val);
-                               got += GiveResourceValue(e, RESOURCE_ROCKETS, op, val);
-                               got += GiveResourceValue(e, RESOURCE_FUEL, op, val);
+                               got += GiveResourceValue(e, RES_CELLS, op, val);
+                               got += GiveResourceValue(e, RES_PLASMA, op, val);
+                               got += GiveResourceValue(e, RES_SHELLS, op, val);
+                               got += GiveResourceValue(e, RES_BULLETS, op, val);
+                               got += GiveResourceValue(e, RES_ROCKETS, op, val);
+                               got += GiveResourceValue(e, RES_FUEL, op, val);
                                break;
                        case "unlimited_ammo":
                                got += GiveBit(e, items, IT_UNLIMITED_AMMO, op, val);
@@ -1806,32 +1805,32 @@ float GiveItems(entity e, float beginarg, float endarg)
                                got += GiveValue(e, superweapons_finished, op, val);
                                break;
                        case "cells":
-                               got += GiveResourceValue(e, RESOURCE_CELLS, op, val);
+                               got += GiveResourceValue(e, RES_CELLS, op, val);
                                break;
                        case "plasma":
-                               got += GiveResourceValue(e, RESOURCE_PLASMA, op, val);
+                               got += GiveResourceValue(e, RES_PLASMA, op, val);
                                break;
                        case "shells":
-                               got += GiveResourceValue(e, RESOURCE_SHELLS, op, val);
+                               got += GiveResourceValue(e, RES_SHELLS, op, val);
                                break;
                        case "nails":
                        case "bullets":
-                               got += GiveResourceValue(e, RESOURCE_BULLETS, op, val);
+                               got += GiveResourceValue(e, RES_BULLETS, op, val);
                                break;
                        case "rockets":
-                               got += GiveResourceValue(e, RESOURCE_ROCKETS, op, val);
+                               got += GiveResourceValue(e, RES_ROCKETS, op, val);
                                break;
                        case "health":
-                               got += GiveResourceValue(e, RESOURCE_HEALTH, op, val);
+                               got += GiveResourceValue(e, RES_HEALTH, op, val);
                                break;
                        case "armor":
-                               got += GiveResourceValue(e, RESOURCE_ARMOR, op, val);
+                               got += GiveResourceValue(e, RES_ARMOR, op, val);
                                break;
                        case "fuel":
-                               got += GiveResourceValue(e, RESOURCE_FUEL, op, val);
+                               got += GiveResourceValue(e, RES_FUEL, op, val);
                                break;
                        default:
-                               FOREACH(Buffs, it != BUFF_Null && Buff_UndeprecateName(cmd) == it.m_name,
+                               FOREACH(Buffs, it != BUFF_Null && Buff_UndeprecateName(cmd) == it.netname,
                                {
                                        got += GiveBuff(e, it, op, val);
                                        break;
@@ -1859,17 +1858,17 @@ float GiveItems(entity e, float beginarg, float endarg)
        POSTGIVE_VALUE(e, strength_finished, 1, SND_POWERUP, SND_POWEROFF);
        POSTGIVE_VALUE(e, invincible_finished, 1, SND_Shield, SND_POWEROFF);
        //POSTGIVE_VALUE(e, superweapons_finished, 1, SND_Null, SND_Null);
-       POSTGIVE_RESOURCE(e, RESOURCE_BULLETS, 0, SND_ITEMPICKUP, SND_Null);
-       POSTGIVE_RESOURCE(e, RESOURCE_CELLS, 0, SND_ITEMPICKUP, SND_Null);
-       POSTGIVE_RESOURCE(e, RESOURCE_PLASMA, 0, SND_ITEMPICKUP, SND_Null);
-       POSTGIVE_RESOURCE(e, RESOURCE_SHELLS, 0, SND_ITEMPICKUP, SND_Null);
-       POSTGIVE_RESOURCE(e, RESOURCE_ROCKETS, 0, SND_ITEMPICKUP, SND_Null);
-       POSTGIVE_RESOURCE_ROT(e, RESOURCE_FUEL, 1, pauserotfuel_finished, autocvar_g_balance_pause_fuel_rot, pauseregen_finished, autocvar_g_balance_pause_fuel_regen, SND_ITEMPICKUP, SND_Null);
-       POSTGIVE_RESOURCE_ROT(e, RESOURCE_ARMOR, 1, pauserotarmor_finished, autocvar_g_balance_pause_armor_rot, pauseregen_finished, autocvar_g_balance_pause_health_regen, SND_ARMOR25, SND_Null);
-       POSTGIVE_RESOURCE_ROT(e, RESOURCE_HEALTH, 1, pauserothealth_finished, autocvar_g_balance_pause_health_rot, pauseregen_finished, autocvar_g_balance_pause_health_regen, SND_MEGAHEALTH, SND_Null);
+       POSTGIVE_RESOURCE(e, RES_BULLETS, 0, SND_ITEMPICKUP, SND_Null);
+       POSTGIVE_RESOURCE(e, RES_CELLS, 0, SND_ITEMPICKUP, SND_Null);
+       POSTGIVE_RESOURCE(e, RES_PLASMA, 0, SND_ITEMPICKUP, SND_Null);
+       POSTGIVE_RESOURCE(e, RES_SHELLS, 0, SND_ITEMPICKUP, SND_Null);
+       POSTGIVE_RESOURCE(e, RES_ROCKETS, 0, SND_ITEMPICKUP, SND_Null);
+       POSTGIVE_RES_ROT(e, RES_FUEL, 1, pauserotfuel_finished, autocvar_g_balance_pause_fuel_rot, pauseregen_finished, autocvar_g_balance_pause_fuel_regen, SND_ITEMPICKUP, SND_Null);
+       POSTGIVE_RES_ROT(e, RES_ARMOR, 1, pauserotarmor_finished, autocvar_g_balance_pause_armor_rot, pauseregen_finished, autocvar_g_balance_pause_health_regen, SND_ARMOR25, SND_Null);
+       POSTGIVE_RES_ROT(e, RES_HEALTH, 1, pauserothealth_finished, autocvar_g_balance_pause_health_rot, pauseregen_finished, autocvar_g_balance_pause_health_regen, SND_MEGAHEALTH, SND_Null);
 
        if(e.superweapons_finished <= 0)
-               if(STAT(WEAPONS, e) & WEPSET_SUPERWEAPONS)
+               if(!g_weaponarena && (STAT(WEAPONS, e) & WEPSET_SUPERWEAPONS))
                        e.superweapons_finished = autocvar_g_balance_superweapons_time;
 
        if(e.strength_finished <= 0)
@@ -1884,6 +1883,10 @@ float GiveItems(entity e, float beginarg, float endarg)
                e.superweapons_finished = 0;
        else
                e.superweapons_finished += time;
+       if(STAT(BUFF_TIME, e) <= 0)
+               STAT(BUFF_TIME, e) = 0;
+       else
+               STAT(BUFF_TIME, e) += time;
 
        for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
        {