]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/common/t_items.qc
Fixed GivePlayerAmmo.
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / t_items.qc
index a48bb7c8c8f31c1141d085aeb43a823684dd322a..6b2428bf7803b4719d304a231d3e8a3525f1a2c1 100644 (file)
@@ -22,6 +22,8 @@
 
     #include <common/weapons/_all.qh>
 
+    #include <common/mutators/mutator/buffs/buffs.qh>
+
     #include "../lib/warpzone/util_server.qh"
 #elif defined(CSQC)
        #include "physics/movetypes/movetypes.qh"
@@ -56,8 +58,7 @@ void Item_SetAlpha(entity this)
                        this.alpha = -1;
        }
 
-       if(!veh_hud)
-       if(this.ItemStatus & ITS_STAYWEP)
+       if((!veh_hud) && (this.ItemStatus & ITS_STAYWEP))
        {
                this.colormod = this.glowmod = autocvar_cl_weapon_stay_color;
                this.alpha = autocvar_cl_weapon_stay_alpha;
@@ -447,28 +448,30 @@ void Item_Show (entity e, float mode)
                e.spawnshieldtime = 1;
                e.ItemStatus &= ~ITS_AVAILABLE;
        }
-       else {
-       bool nostay = def.instanceOfWeaponPickup ? !!(def.m_weapon.weapons & WEPSET_SUPERWEAPONS) : false // no weapon-stay on superweapons
-               || e.team // weapon stay isn't supported for teamed weapons
-               ;
-       if(def.instanceOfWeaponPickup && !nostay && g_weapon_stay)
-       {
-               // make the item translucent and not touchable
-               e.model = e.mdl;
-               e.solid = SOLID_TRIGGER; // can STILL be picked up!
-               e.effects |= EF_STARDUST;
-               e.spawnshieldtime = 0; // field indicates whether picking it up may give you anything other than the weapon
-               e.ItemStatus |= (ITS_AVAILABLE | ITS_STAYWEP);
-       }
        else
        {
-               //setmodel(e, "null");
-               e.solid = SOLID_NOT;
-               e.colormod = '0 0 0';
-               //e.glowmod = e.colormod;
-               e.spawnshieldtime = 1;
-               e.ItemStatus &= ~ITS_AVAILABLE;
-       }}
+               bool nostay = def.instanceOfWeaponPickup ? !!(def.m_weapon.weapons & WEPSET_SUPERWEAPONS) : false // no weapon-stay on superweapons
+                       || e.team // weapon stay isn't supported for teamed weapons
+                       ;
+               if(def.instanceOfWeaponPickup && !nostay && g_weapon_stay)
+               {
+                       // make the item translucent and not touchable
+                       e.model = e.mdl;
+                       e.solid = SOLID_TRIGGER; // can STILL be picked up!
+                       e.effects |= EF_STARDUST;
+                       e.spawnshieldtime = 0; // field indicates whether picking it up may give you anything other than the weapon
+                       e.ItemStatus |= (ITS_AVAILABLE | ITS_STAYWEP);
+               }
+               else
+               {
+                       //setmodel(e, "null");
+                       e.solid = SOLID_NOT;
+                       e.colormod = '0 0 0';
+                       //e.glowmod = e.colormod;
+                       e.spawnshieldtime = 1;
+                       e.ItemStatus &= ~ITS_AVAILABLE;
+               }
+       }
 
        if (def.m_glow)
                e.ItemStatus |= ITS_GLOW;
@@ -507,7 +510,7 @@ void Item_Respawn (entity this)
        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) || this.weapons & WEPSET_SUPERWEAPONS)
+    if (Item_ItemsTime_Allow(this.itemdef) || (this.weapons & WEPSET_SUPERWEAPONS))
        {
                float t = Item_ItemsTime_UpdateTime(this, 0);
                Item_ItemsTime_SetTime(this, t);
@@ -535,7 +538,6 @@ void Item_RespawnCountdown (entity this)
                this.count += 1;
                if(this.count == 1)
                {
-                       MUTATOR_CALLHOOK(Item_RespawnCountdown, string_null, '0 0 0');
                        do {
                                {
                                        entity wi = Weapons_from(this.weapon);
@@ -554,10 +556,11 @@ void Item_RespawnCountdown (entity this)
                                        }
                                }
                        } while (0);
+                       bool mutator_returnvalue = MUTATOR_CALLHOOK(Item_RespawnCountdown, this);
             if(this.waypointsprite_attached)
             {
                 GameItem def = this.itemdef;
-                if (Item_ItemsTime_SpectatorOnly(def))
+                if (Item_ItemsTime_SpectatorOnly(def) && !mutator_returnvalue)
                     WaypointSprite_UpdateRule(this.waypointsprite_attached, 0, SPRITERULE_SPECTATOR);
                 WaypointSprite_UpdateBuildFinished(this.waypointsprite_attached, time + ITEM_RESPAWN_TICKS);
             }
@@ -592,15 +595,18 @@ void Item_RespawnThink(entity this)
 void Item_ScheduleRespawnIn(entity e, float t)
 {
        // if the respawn time is longer than 10 seconds, show a waypoint, otherwise, just respawn normally
-       if ((Item_ItemsTime_Allow(e.itemdef) || e.weapons & WEPSET_SUPERWEAPONS) && (t - ITEM_RESPAWN_TICKS) > 0)
+       if ((Item_ItemsTime_Allow(e.itemdef) || (e.weapons & WEPSET_SUPERWEAPONS) || MUTATOR_CALLHOOK(Item_ScheduleRespawn, e, t)) && (t - ITEM_RESPAWN_TICKS) > 0)
        {
                setthink(e, Item_RespawnCountdown);
                e.nextthink = time + max(0, t - ITEM_RESPAWN_TICKS);
                e.scheduledrespawntime = e.nextthink + ITEM_RESPAWN_TICKS;
                e.count = 0;
-               t = Item_ItemsTime_UpdateTime(e, e.scheduledrespawntime);
-               Item_ItemsTime_SetTime(e, t);
-               Item_ItemsTime_SetTimesForAllPlayers();
+               if(Item_ItemsTime_Allow(e.itemdef) || (e.weapons & WEPSET_SUPERWEAPONS))
+               {
+                       t = Item_ItemsTime_UpdateTime(e, e.scheduledrespawntime);
+                       Item_ItemsTime_SetTime(e, t);
+                       Item_ItemsTime_SetTimesForAllPlayers();
+               }
        }
        else
        {
@@ -608,6 +614,13 @@ void Item_ScheduleRespawnIn(entity e, float t)
                e.nextthink = time;
                e.scheduledrespawntime = time + t;
                e.wait = time + t;
+
+               if(Item_ItemsTime_Allow(e.itemdef) || (e.weapons & WEPSET_SUPERWEAPONS))
+               {
+                       t = Item_ItemsTime_UpdateTime(e, e.scheduledrespawntime);
+                       Item_ItemsTime_SetTime(e, t);
+                       Item_ItemsTime_SetTimesForAllPlayers();
+               }
        }
 }
 
@@ -625,7 +638,70 @@ void Item_ScheduleRespawn(entity e)
 void Item_ScheduleInitialRespawn(entity e)
 {
        Item_Show(e, 0);
-       Item_ScheduleRespawnIn(e, game_starttime - time + ((e.respawntimestart) ? e.respawntimestart : ITEM_RESPAWNTIME_INITIAL(e)));
+       Item_ScheduleRespawnIn(e, max(0, game_starttime - time) + ((e.respawntimestart) ? e.respawntimestart : ITEM_RESPAWNTIME_INITIAL(e)));
+}
+
+void GivePlayerHealth(entity player, float amount)
+{
+       if (amount == 0)
+       {
+               return;
+       }
+       player.health = bound(player.health, player.health + amount,
+                g_pickup_healthmega_max);
+       player.pauserothealth_finished = max(player.pauserothealth_finished, time +
+               autocvar_g_balance_pause_health_rot);
+}
+
+void GivePlayerArmor(entity player, float amount)
+{
+       if (amount == 0)
+       {
+               return;
+       }
+       player.armorvalue = bound(player.armorvalue, player.armorvalue + amount,
+                g_pickup_armormega_max);
+       player.pauserotarmor_finished = max(player.pauserotarmor_finished, time +
+               autocvar_g_balance_pause_armor_rot);
+}
+
+void GivePlayerAmmo(entity player, .float ammotype, float amount)
+{
+       float maxvalue = 999;
+       switch (ammotype)
+       {
+               case ammo_shells:
+               {
+                       maxvalue = g_pickup_shells_max;
+                       break;
+               }
+               case ammo_cells:
+               {
+                       maxvalue = g_pickup_cells_max;
+                       break;
+               }
+               case ammo_rockets:
+               {
+                       maxvalue = g_pickup_rockets_max;
+                       break;
+               }
+               case ammo_plasma:
+               {
+                       maxvalue = g_pickup_plasma_max;
+                       break;
+               }
+               case ammo_nails:
+               {
+                       maxvalue = g_pickup_nails_max;
+                       break;
+               }
+               case ammo_fuel:
+               {
+                       maxvalue = g_pickup_fuel_max;
+                       break;
+               }
+       }
+       player.(ammotype) = min(player.(ammotype) + amount, maxvalue);
 }
 
 float Item_GiveAmmoTo(entity item, entity player, .float ammotype, float ammomax, float mode)
@@ -871,7 +947,7 @@ LABEL(pickup)
                                }
                        });
                        e = RandomSelection_chosen_ent;
-
+                       Item_Show(e, 1); // reset its state so it is visible (extra sendflags doesn't matter, this happens anyway)
                }
                else
                        e = this;
@@ -949,133 +1025,116 @@ float generic_pickupevalfunc(entity player, entity item) {return item.bot_pickup
 
 float weapon_pickupevalfunc(entity player, entity item)
 {
-       float c;
-       int rating = item.bot_pickupbasevalue;
-
        // See if I have it already
        if(player.weapons & item.weapons)
        {
                // If I can pick it up
                if(!item.spawnshieldtime)
-                       c = 0;
-               else if(player.ammo_cells || player.ammo_shells || player.ammo_plasma || player.ammo_nails || player.ammo_rockets)
-               {
-                       if (rating > 0)
-                               rating = BOT_PICKUP_RATING_LOW * 0.5 * (1 + rating / BOT_PICKUP_RATING_HIGH);
-                       // Skilled bots will grab more
-                       c = 1 + bound(0, skill / 10, 1) * 0.5;
-               }
-               else
-                       c = 0;
+                       return 0;
+               return ammo_pickupevalfunc(player, item);
        }
-       else
-               c = 1;
 
-       if (c <= 0)
-               return 0;
+       // reduce weapon value if bot already got a good arsenal
+       float c = 1;
+       int weapons_value = 0;
+       FOREACH(Weapons, it != WEP_Null && (player.weapons & it.m_wepset), {
+               weapons_value += it.bot_pickupbasevalue;
+       });
+       c -= bound(0, weapons_value / 20000, 1) * 0.5;
+
+       return item.bot_pickupbasevalue * c;
+}
 
-       // If custom weapon priorities for bots is enabled rate most wanted weapons higher
-       if(bot_custom_weapon)
+float ammo_pickupevalfunc(entity player, entity item)
+{
+       bool need_shells = false, need_nails = false, need_rockets = false, need_cells = false, need_plasma = false, need_fuel = false;
+       entity wpn = NULL;
+       float c = 0;
+       float rating = 0;
+
+       // Detect needed ammo
+       if(item.itemdef.instanceOfWeaponPickup)
        {
-               int best_ratio = 0;
-               int missing = 0;
+               entity ammo = NULL;
+               if(item.ammo_shells)       { need_shells  = true; ammo = ITEM_Shells;      }
+               else if(item.ammo_nails)   { need_nails   = true; ammo = ITEM_Bullets;     }
+               else if(item.ammo_rockets) { need_rockets = true; ammo = ITEM_Rockets;     }
+               else if(item.ammo_cells)   { need_cells   = true; ammo = ITEM_Cells;       }
+               else if(item.ammo_plasma)  { need_plasma  = true; ammo = ITEM_Plasma;      }
+               else if(item.ammo_fuel)    { need_fuel    = true; ammo = ITEM_JetpackFuel; }
 
-               // evaluate weapon usefulness in all ranges
-               for(int list = 0; list < 3; list++)
-               {
-                       int position = -1;
-                       int wep_count = 0;
-                       int wpn = item.weapon;
-                       for (int j = 0; j < WEP_LAST; ++j)
-                       {
-                               int list_wpn = 0;
-                               if (list == 0) list_wpn = bot_weapons_far[j];
-                               else if (list == 1) list_wpn = bot_weapons_mid[j];
-                               else list_wpn = bot_weapons_close[j];
+               if(!ammo)
+                       return 0;
+               wpn = item;
+               rating = ammo.m_botvalue;
+       }
+       else
+       {
+               FOREACH(Weapons, it != WEP_Null, {
+                       if(!(player.weapons & (it.m_wepset)))
+                               continue;
 
-                               if (weaponsInMap & Weapons_from(list_wpn).m_wepset) // only if available
-                               {
-                                       if (list_wpn > 0)
-                                               wep_count++;
-                                       if (position == -1 && list_wpn == wpn)
-                                               position = wep_count;
-                               }
-                       }
-                       if (position == -1)
+                       switch(it.ammo_field)
                        {
-                               missing++;
-                               position = wep_count; // if missing assume last
+                               case ammo_shells:  need_shells  = true; break;
+                               case ammo_nails:   need_nails   = true; break;
+                               case ammo_rockets: need_rockets = true; break;
+                               case ammo_cells:   need_cells   = true; break;
+                               case ammo_plasma:  need_plasma  = true; break;
+                               case ammo_fuel:    need_fuel    = true; break;
                        }
-                       if (wep_count)
-                       {
-                               if (!best_ratio || position / wep_count < best_ratio)
-                                       best_ratio = position / wep_count;
-                       }
-               }
-
-               if (missing < 3 && best_ratio)
-                       c = c - best_ratio * 0.3;
+               });
+               rating = item.bot_pickupbasevalue;
        }
 
-       return rating * c;
+       if ((need_shells) && (item.ammo_shells) && (player.ammo_shells < g_pickup_shells_max))
+               c = item.ammo_shells / player.ammo_shells;
+
+       if ((need_nails) && (item.ammo_nails) && (player.ammo_nails < g_pickup_nails_max))
+               c = item.ammo_nails / player.ammo_nails;
+
+       if ((need_rockets) && (item.ammo_rockets) && (player.ammo_rockets < g_pickup_rockets_max))
+               c = item.ammo_rockets / player.ammo_rockets;
+
+       if ((need_cells) && (item.ammo_cells) && (player.ammo_cells < g_pickup_cells_max))
+               c = item.ammo_cells / player.ammo_cells;
+
+       if ((need_plasma) && (item.ammo_plasma) && (player.ammo_plasma < g_pickup_plasma_max))
+               c = item.ammo_plasma / player.ammo_plasma;
+
+       if ((need_fuel) && (item.ammo_fuel) && (player.ammo_fuel < g_pickup_fuel_max))
+               c = item.ammo_fuel / player.ammo_fuel;
+
+       rating *= min(2, c);
+       if(wpn)
+               rating += wpn.bot_pickupbasevalue * 0.1;
+       return rating;
 }
 
-float commodity_pickupevalfunc(entity player, entity item)
+.int item_group;
+.int item_group_count;
+float healtharmor_pickupevalfunc(entity player, entity item)
 {
-       bool need_shells = false, need_nails = false, need_rockets = false, need_cells = false, need_plasma = false, need_fuel = false;
        float c = 0;
+       float rating = item.bot_pickupbasevalue;
 
-       // Detect needed ammo
-       FOREACH(Weapons, it != WEP_Null, {
-               if(!(player.weapons & (it.m_wepset)))
-                       continue;
+       float itemarmor = item.armorvalue;
+       float itemhealth = item.health;
 
-               switch(it.ammo_field)
-               {
-                       case ammo_shells:  need_shells  = true; break;
-                       case ammo_nails:   need_nails   = true; break;
-                       case ammo_rockets: need_rockets = true; break;
-                       case ammo_cells:   need_cells   = true; break;
-                       case ammo_plasma:  need_plasma  = true; break;
-                       case ammo_fuel:    need_fuel    = true; break;
-               }
-       });
+       if(item.item_group)
+       {
+               itemarmor *= min(4, item.item_group_count);
+               itemhealth *= min(4, item.item_group_count);
+       }
 
-       // TODO: figure out if the player even has the weapon this ammo is for?
-       // may not affect strategy much though...
-       // find out how much more ammo/armor/health the player can hold
-       if (need_shells)
-       if (item.ammo_shells)
-       if (player.ammo_shells < g_pickup_shells_max)
-               c = c + max(0, 1 - player.ammo_shells / g_pickup_shells_max);
-       if (need_nails)
-       if (item.ammo_nails)
-       if (player.ammo_nails < g_pickup_nails_max)
-               c = c + max(0, 1 - player.ammo_nails / g_pickup_nails_max);
-       if (need_rockets)
-       if (item.ammo_rockets)
-       if (player.ammo_rockets < g_pickup_rockets_max)
-               c = c + max(0, 1 - player.ammo_rockets / g_pickup_rockets_max);
-       if (need_cells)
-       if (item.ammo_cells)
-       if (player.ammo_cells < g_pickup_cells_max)
-               c = c + max(0, 1 - player.ammo_cells / g_pickup_cells_max);
-       if (need_plasma)
-       if (item.ammo_plasma)
-       if (player.ammo_plasma < g_pickup_plasma_max)
-               c = c + max(0, 1 - player.ammo_plasma / g_pickup_plasma_max);
-       if (need_fuel)
-       if (item.ammo_fuel)
-       if (player.ammo_fuel < g_pickup_fuel_max)
-               c = c + max(0, 1 - player.ammo_fuel / g_pickup_fuel_max);
-       if (item.armorvalue)
-       if (player.armorvalue < item.max_armorvalue)
-               c = c + max(0, 1 - player.armorvalue / item.max_armorvalue);
-       if (item.health)
-       if (player.health < item.max_health)
-               c = c + max(0, 1 - player.health / item.max_health);
+       if (itemarmor && (player.armorvalue < item.max_armorvalue))
+               c = itemarmor / max(1, player.armorvalue * 2/3 + player.health * 1/3);
 
-       return item.bot_pickupbasevalue * c;
+       if (itemhealth && (player.health < item.max_health))
+               c = itemhealth / max(1, player.health);
+
+       rating *= min(2, c);
+       return rating;
 }
 
 void Item_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
@@ -1104,12 +1163,18 @@ void _StartItem(entity this, entity def, float defaultrespawntime, float default
        this.item_model_ent = itemmodel;
     this.item_pickupsound_ent = pickupsound;
 
+    if(def.m_iteminit)
+       def.m_iteminit(this);
+
        if(!this.respawntime) // both need to be set
        {
                this.respawntime = defaultrespawntime;
                this.respawntimejitter = defaultrespawntimejitter;
        }
 
+       if(!this.pickup_anyway && def.m_pickupanyway)
+               this.pickup_anyway = def.m_pickupanyway();
+
        int itemid = def.m_itemid;
        this.items = itemid;
        int weaponid = def.instanceOfWeaponPickup ? def.m_weapon.m_id : 0;
@@ -1293,6 +1358,8 @@ void _StartItem(entity this, entity def, float defaultrespawntime, float default
                delete(this);
                return;
        }
+
+       setItemGroup(this);
 }
 
 void StartItem(entity this, GameItem def)
@@ -1305,20 +1372,63 @@ void StartItem(entity this, GameItem def)
        );
 }
 
+#define IS_SMALL(def) ((def.instanceOfHealth && def == ITEM_HealthSmall) || (def.instanceOfArmor && def == ITEM_ArmorSmall))
+int group_count = 1;
+
+void setItemGroup(entity this)
+{
+       if(!IS_SMALL(this.itemdef))
+               return;
+
+       FOREACH_ENTITY_RADIUS(this.origin, 120, (it != this) && IS_SMALL(it.itemdef),
+       {
+               if(!this.item_group)
+               {
+                       if(!it.item_group)
+                       {
+                               it.item_group = group_count;
+                               group_count++;
+                       }
+                       this.item_group = it.item_group;
+               }
+               else // spawning item is already part of a item_group X
+               {
+                       if(!it.item_group)
+                               it.item_group = this.item_group;
+                       else if(it.item_group != this.item_group) // found an item near the spawning item that is part of a different item_group Y
+                       {
+                               int grY = it.item_group;
+                               // move all items of item_group Y to item_group X
+                               IL_EACH(g_items, IS_SMALL(it.itemdef),
+                               {
+                                       if(it.item_group == grY)
+                                               it.item_group = this.item_group;
+                               });
+                       }
+               }
+       });
+}
+
+void setItemGroupCount()
+{
+       for (int k = 1; k <= group_count; k++)
+       {
+               int count = 0;
+               IL_EACH(g_items, IS_SMALL(it.itemdef) && it.item_group == k, { count++; });
+               if (count)
+                       IL_EACH(g_items, IS_SMALL(it.itemdef) && it.item_group == k, { it.item_group_count = count; });
+       }
+}
+
 spawnfunc(item_rockets)
 {
-       if(!this.ammo_rockets)
-               this.ammo_rockets = g_pickup_rockets;
-       if(!this.pickup_anyway)
-               this.pickup_anyway = g_pickup_ammo_anyway;
     StartItem(this, ITEM_Rockets);
 }
 
 spawnfunc(item_bullets)
 {
-       if(!weaponswapping)
-       if(autocvar_sv_q3acompat_machineshotgunswap)
-       if(this.classname != "droppedweapon")
+       if(!weaponswapping && autocvar_sv_q3acompat_machineshotgunswap && 
+          (this.classname != "droppedweapon"))
        {
                weaponswapping = true;
                spawnfunc_item_shells(this);
@@ -1326,36 +1436,23 @@ spawnfunc(item_bullets)
                return;
        }
 
-       if(!this.ammo_nails)
-               this.ammo_nails = g_pickup_nails;
-       if(!this.pickup_anyway)
-               this.pickup_anyway = g_pickup_ammo_anyway;
     StartItem(this, ITEM_Bullets);
 }
 
 spawnfunc(item_cells)
 {
-       if(!this.ammo_cells)
-               this.ammo_cells = g_pickup_cells;
-       if(!this.pickup_anyway)
-               this.pickup_anyway = g_pickup_ammo_anyway;
        StartItem(this, ITEM_Cells);
 }
 
 spawnfunc(item_plasma)
 {
-       if(!this.ammo_plasma)
-               this.ammo_plasma = g_pickup_plasma;
-       if(!this.pickup_anyway)
-               this.pickup_anyway = g_pickup_ammo_anyway;
        StartItem(this, ITEM_Plasma);
 }
 
 spawnfunc(item_shells)
 {
-       if(!weaponswapping)
-       if(autocvar_sv_q3acompat_machineshotgunswap)
-       if(this.classname != "droppedweapon")
+       if(!weaponswapping && autocvar_sv_q3acompat_machineshotgunswap &&
+          (this.classname != "droppedweapon"))
        {
                weaponswapping = true;
                spawnfunc_item_bullets(this);
@@ -1363,98 +1460,46 @@ spawnfunc(item_shells)
                return;
        }
 
-       if(!this.ammo_shells)
-               this.ammo_shells = g_pickup_shells;
-       if(!this.pickup_anyway)
-               this.pickup_anyway = g_pickup_ammo_anyway;
        StartItem(this, ITEM_Shells);
 }
 
 spawnfunc(item_armor_small)
 {
-       if(!this.armorvalue)
-               this.armorvalue = g_pickup_armorsmall;
-       if(!this.max_armorvalue)
-               this.max_armorvalue = g_pickup_armorsmall_max;
-       if(!this.pickup_anyway)
-               this.pickup_anyway = g_pickup_armorsmall_anyway;
        StartItem(this, ITEM_ArmorSmall);
 }
 
 spawnfunc(item_armor_medium)
 {
-       if(!this.armorvalue)
-               this.armorvalue = g_pickup_armormedium;
-       if(!this.max_armorvalue)
-               this.max_armorvalue = g_pickup_armormedium_max;
-       if(!this.pickup_anyway)
-               this.pickup_anyway = g_pickup_armormedium_anyway;
        StartItem(this, ITEM_ArmorMedium);
 }
 
 spawnfunc(item_armor_big)
 {
-       if(!this.armorvalue)
-               this.armorvalue = g_pickup_armorbig;
-       if(!this.max_armorvalue)
-               this.max_armorvalue = g_pickup_armorbig_max;
-       if(!this.pickup_anyway)
-               this.pickup_anyway = g_pickup_armorbig_anyway;
        StartItem(this, ITEM_ArmorBig);
 }
 
 spawnfunc(item_armor_mega)
 {
-       if(!this.armorvalue)
-               this.armorvalue = g_pickup_armormega;
-       if(!this.max_armorvalue)
-               this.max_armorvalue = g_pickup_armormega_max;
-       if(!this.pickup_anyway)
-               this.pickup_anyway = g_pickup_armormega_anyway;
        StartItem(this, ITEM_ArmorMega);
 }
 
 spawnfunc(item_health_small)
 {
-       if(!this.max_health)
-               this.max_health = g_pickup_healthsmall_max;
-       if(!this.health)
-               this.health = g_pickup_healthsmall;
-       if(!this.pickup_anyway)
-               this.pickup_anyway = g_pickup_healthsmall_anyway;
        StartItem(this, ITEM_HealthSmall);
 }
 
 spawnfunc(item_health_medium)
 {
-       if(!this.max_health)
-               this.max_health = g_pickup_healthmedium_max;
-       if(!this.health)
-               this.health = g_pickup_healthmedium;
-       if(!this.pickup_anyway)
-               this.pickup_anyway = g_pickup_healthmedium_anyway;
     StartItem(this, ITEM_HealthMedium);
 }
 
 spawnfunc(item_health_big)
 {
-       if(!this.max_health)
-               this.max_health = g_pickup_healthbig_max;
-       if(!this.health)
-               this.health = g_pickup_healthbig;
-       if(!this.pickup_anyway)
-               this.pickup_anyway = g_pickup_healthbig_anyway;
        StartItem(this, ITEM_HealthBig);
 }
 
 spawnfunc(item_health_mega)
 {
-    if(!this.max_health)
-        this.max_health = g_pickup_healthmega_max;
-    if(!this.health)
-        this.health = g_pickup_healthmega;
-    if(!this.pickup_anyway)
-        this.pickup_anyway = g_pickup_healthmega_anyway;
     StartItem(this, ITEM_HealthMega);
 }
 
@@ -1469,16 +1514,12 @@ spawnfunc(item_health100) { spawnfunc_item_health_mega(this); }
 
 spawnfunc(item_strength)
 {
-               if(!this.strength_finished)
-                       this.strength_finished = autocvar_g_balance_powerup_strength_time;
-               StartItem(this, ITEM_Strength);
+       StartItem(this, ITEM_Strength);
 }
 
 spawnfunc(item_invincible)
 {
-               if(!this.invincible_finished)
-                       this.invincible_finished = autocvar_g_balance_powerup_invincible_time;
-               StartItem(this, ITEM_Shield);
+       StartItem(this, ITEM_Shield);
 }
 
 // compatibility:
@@ -1493,10 +1534,9 @@ void target_items_use(entity this, entity actor, entity trigger)
                return;
        }
 
-       if (!IS_PLAYER(actor))
-               return;
-       if(IS_DEAD(actor))
+       if (!IS_PLAYER(actor) || IS_DEAD(actor))
                return;
+
        if(trigger.solid == SOLID_TRIGGER)
        {
                EXACTTRIGGER_TOUCH(this, trigger);
@@ -1513,7 +1553,7 @@ void target_items_use(entity this, entity actor, entity trigger)
 
 spawnfunc(target_items)
 {
-       int n, j;
+       int n;
        string s;
 
        this.use = target_items_use;
@@ -1531,7 +1571,7 @@ spawnfunc(target_items)
        }
        else
        {
-               for(j = 0; j < n; ++j)
+               for(int j = 0; j < n; ++j)
                {
                        if     (argv(j) == "unlimited_ammo")         this.items |= IT_UNLIMITED_AMMO;
                        else if(argv(j) == "unlimited_weapon_ammo")  this.items |= IT_UNLIMITED_WEAPON_AMMO;
@@ -1543,6 +1583,15 @@ spawnfunc(target_items)
                        else if(argv(j) == "fuel_regen")             this.items |= ITEM_JetpackRegen.m_itemid;
                        else
                        {
+                               FOREACH(Buffs, it != BUFF_Null,
+                               {
+                                       s = Buff_UndeprecateName(argv(j));
+                                       if(s == it.m_name)
+                                       {
+                                               this.buffs |= (it.m_itemid);
+                                               break;
+                                       }
+                               });
                                FOREACH(Weapons, it != WEP_Null, {
                                        s = W_UndeprecateName(argv(j));
                                        if(s == it.netname)
@@ -1599,13 +1648,14 @@ spawnfunc(target_items)
                if(this.ammo_fuel != 0) this.netname = sprintf("%s %s%d %s", this.netname, valueprefix, max(0, this.ammo_fuel), "fuel");
                if(this.health != 0) this.netname = sprintf("%s %s%d %s", this.netname, valueprefix, max(0, this.health), "health");
                if(this.armorvalue != 0) this.netname = sprintf("%s %s%d %s", this.netname, valueprefix, max(0, this.armorvalue), "armor");
+               FOREACH(Buffs, it != BUFF_Null, this.netname = sprintf("%s %s%d %s", this.netname, itemprefix, !!(this.buffs & (it.m_itemid)), it.m_name));
                FOREACH(Weapons, it != WEP_Null, this.netname = sprintf("%s %s%d %s", this.netname, itemprefix, !!(this.weapons & (it.m_wepset)), it.netname));
        }
        this.netname = strzone(this.netname);
        //print(this.netname, "\n");
 
        n = tokenize_console(this.netname);
-       for(j = 0; j < n; ++j)
+       for(int j = 0; j < n; ++j)
        {
                FOREACH(Weapons, it != WEP_Null && W_UndeprecateName(argv(j)) == it.netname, {
             it.wr_init(it);
@@ -1616,10 +1666,6 @@ spawnfunc(target_items)
 
 spawnfunc(item_fuel)
 {
-       if(!this.ammo_fuel)
-               this.ammo_fuel = g_pickup_fuel;
-       if(!this.pickup_anyway)
-               this.pickup_anyway = g_pickup_ammo_anyway;
        StartItem(this, ITEM_JetpackFuel);
 }
 
@@ -1635,8 +1681,6 @@ spawnfunc(item_fuel_regen)
 
 spawnfunc(item_jetpack)
 {
-       if(!this.ammo_fuel)
-               this.ammo_fuel = g_pickup_fuel_jetpack;
        if(start_items & ITEM_Jetpack.m_itemid)
        {
                spawnfunc_item_fuel(this);
@@ -1676,6 +1720,35 @@ float GiveWeapon(entity e, float wpn, float op, float val)
        return (v0 != v1);
 }
 
+bool GiveBuff(entity e, Buff thebuff, int op, int val)
+{
+       bool had_buff = (e.buffs & thebuff.m_itemid);
+       switch(op)
+       {
+               case OP_SET:
+                       if(val > 0)
+                               e.buffs |= thebuff.m_itemid;
+                       else
+                               e.buffs &= ~thebuff.m_itemid;
+                       break;
+               case OP_MIN:
+               case OP_PLUS:
+                       if(val > 0)
+                               e.buffs |= thebuff.m_itemid;
+                       break;
+               case OP_MAX:
+                       if(val <= 0)
+                               e.buffs &= ~thebuff.m_itemid;
+                       break;
+               case OP_MINUS:
+                       if(val > 0)
+                               e.buffs &= ~thebuff.m_itemid;
+                       break;
+       }
+       bool have_buff = (e.buffs & thebuff.m_itemid);
+       return (had_buff != have_buff);
+}
+
 void GiveSound(entity e, float v0, float v1, float t, Sound snd_incr, Sound snd_decr)
 {
        if(v1 == v0)
@@ -1779,6 +1852,8 @@ float GiveItems(entity e, float beginarg, float endarg)
                                got += GiveValue(e, armorvalue, op, val);
                        case "allweapons":
                                FOREACH(Weapons, it != WEP_Null && !(it.spawnflags & WEP_FLAG_MUTATORBLOCKED), 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 += GiveValue(e, ammo_cells, op, val);
                                got += GiveValue(e, ammo_plasma, op, val);
@@ -1837,6 +1912,11 @@ float GiveItems(entity e, float beginarg, float endarg)
                                got += GiveValue(e, ammo_fuel, op, val);
                                break;
                        default:
+                               FOREACH(Buffs, it != BUFF_Null && Buff_UndeprecateName(cmd) == it.m_name,
+                               {
+                                       got += GiveBuff(e, it, op, val);
+                                       break;
+                               });
                                FOREACH(Weapons, it != WEP_Null && W_UndeprecateName(cmd) == it.netname, {
                     got += GiveWeapon(e, it.m_id, op, val);
                     break;
@@ -1900,7 +1980,11 @@ float GiveItems(entity e, float beginarg, float endarg)
                {
                        .entity weaponentity = weaponentities[slot];
                        if(_switchweapon & BIT(slot))
-                               W_SwitchWeapon_Force(e, w_getbestweapon(e, weaponentity), weaponentity);
+                       {
+                               Weapon wep = w_getbestweapon(e, weaponentity);
+                               if(wep != e.(weaponentity).m_switchweapon)
+                                       W_SwitchWeapon_Force(e, wep, weaponentity);
+                       }
                }
        }