]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/server/t_items.qc
Merge branch 'master' into mirceakitsune/damage_effects
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / t_items.qc
index a96bc50bc6ff22c9446c58f463c106598c83f775..11688ae36a67cbdca3117edb78df76df93f94786 100644 (file)
@@ -5,7 +5,7 @@ float have_pickup_item(void)
                if(self.classname != "minstagib")
                        return FALSE;
 
-       if(self.items == IT_STRENGTH || self.items == IT_INVINCIBLE)
+       if(self.flags & FL_POWERUP)
        {
                if(autocvar_g_powerups > 0)
                        return TRUE;
@@ -131,7 +131,7 @@ void Item_Show (entity e, float mode)
 
                e.spawnshieldtime = 1;
        }
-       else if((e.flags & FL_WEAPON) && g_weapon_stay)
+       else if((e.flags & FL_WEAPON) && !(e.flags & FL_NO_WEAPON_STAY) && g_weapon_stay)
        {
                // make the item translucent and not touchable
                e.model = e.mdl;
@@ -233,6 +233,20 @@ void Item_RespawnCountdown (void)
                                case IT_FUEL_REGEN:     name = "item-fuelregen"; rgb = '1 0.5 0'; break;
                                case IT_JETPACK:        name = "item-jetpack"; rgb = '0.5 0.5 0.5'; break;
                        }
+                       if(self.flags & FL_WEAPON)
+                       {
+                               entity wi = get_weaponinfo(self.weapon);
+                               if(wi)
+                               {
+                                       name = wi.model2;
+                                       rgb = '1 0 0';
+                               }
+                       }
+                       if(!name)
+                       {
+                               print("Unknown powerup-marked item is wanting to respawn\n");
+                               localcmd(sprintf("prvm_edict server %d\n", num_for_edict(self)));
+                       }
                        if(name)
                        {
                                WaypointSprite_Spawn(name, 0, 0, self, '0 0 64', world, 0, self, waypointsprite_attached, TRUE, RADARICON_POWERUP, rgb);
@@ -251,7 +265,7 @@ void Item_RespawnCountdown (void)
 
 void Item_ScheduleRespawnIn(entity e, float t)
 {
-       if(e.flags & FL_POWERUP)
+       if((e.flags & FL_POWERUP) || (e.weapons & WEPBIT_SUPERWEAPONS))
        {
                e.think = Item_RespawnCountdown;
                e.nextthink = time + max(0, t - ITEM_RESPAWN_TICKS);
@@ -281,6 +295,53 @@ void Item_ScheduleInitialRespawn(entity e)
        Item_ScheduleRespawnIn(e, game_starttime - time + ITEM_RESPAWNTIME_INITIAL(e));
 }
 
+float ITEM_MODE_NONE = 0;
+float ITEM_MODE_HEALTH = 1;
+float ITEM_MODE_ARMOR = 2;
+float ITEM_MODE_FUEL = 3;
+float Item_GiveAmmoTo(entity item, entity player, .float ammofield, float ammomax, float mode)
+{
+       if (!item.ammofield)
+               return FALSE;
+
+       if (item.spawnshieldtime)
+       {
+               if ((player.ammofield < ammomax) || item.pickup_anyway)
+               {
+                       player.ammofield = bound(player.ammofield, ammomax, player.ammofield + item.ammofield);
+                       goto YEAH;
+               }
+       }
+       else if(g_weapon_stay == 2)
+       {
+               float mi = min(item.ammofield, ammomax);
+               if (player.ammofield < mi)
+               {
+                       player.ammofield = mi;
+                       goto YEAH;
+               }
+       }
+
+       return FALSE;
+
+:YEAH
+       switch(mode)
+       {
+               case ITEM_MODE_FUEL:
+                       player.pauserotfuel_finished = max(player.pauserotfuel_finished, time + autocvar_g_balance_pause_fuel_rot);
+                       break;
+               case ITEM_MODE_HEALTH:
+                       player.pauserothealth_finished = max(player.pauserothealth_finished, time + autocvar_g_balance_pause_health_rot);
+                       break;
+               case ITEM_MODE_ARMOR:
+                       player.pauserotarmor_finished = max(player.pauserotarmor_finished, time + autocvar_g_balance_pause_armor_rot);
+                       break;
+               default:
+                       break;
+       }
+       return TRUE;
+}
+
 float Item_GiveTo(entity item, entity player)
 {
        float _switchweapon;
@@ -295,72 +356,67 @@ float Item_GiveTo(entity item, entity player)
 
        if (g_minstagib)
        {
-               if(item.spawnshieldtime)
+               float prevcells = player.ammo_cells;
+
+               pickedup |= Item_GiveAmmoTo(item, player, ammo_fuel, g_pickup_fuel_max, ITEM_MODE_FUEL);
+               pickedup |= Item_GiveAmmoTo(item, player, ammo_cells, 999, ITEM_MODE_NONE);
+
+               if(player.ammo_cells > prevcells)
                {
-                       if (item.ammo_fuel)
-                       if (player.ammo_fuel < g_pickup_fuel_max)
-                       {
-                               pickedup = TRUE;
-                               player.ammo_fuel = bound(player.ammo_fuel, g_pickup_fuel_max, player.ammo_fuel + item.ammo_fuel);
-                               player.pauserotfuel_finished = max(player.pauserotfuel_finished, time + autocvar_g_balance_pause_fuel_rot);
-                       }
-                       if((it = (item.items - (item.items & player.items)) & IT_PICKUPMASK))
+                       _switchweapon = TRUE;
+
+                       // play some cool sounds ;)
+                       if (clienttype(player) == CLIENTTYPE_REAL)
                        {
-                               pickedup = TRUE;
-                               player.items |= it;
-                               sprint (player, strcat("You got the ^2", item.netname, "\n"));
+                               if(player.health <= 5)
+                                       AnnounceTo(player, "lastsecond");
+                               else if(player.health < 50)
+                                       AnnounceTo(player, "narrowly");
                        }
+                       // sound not available
+                       // else if(item.items == IT_CELLS)
+                       //      AnnounceTo(player, "ammo");
 
-                       _switchweapon = TRUE;
+                       if (item.weapons & WEPBIT_MINSTANEX)
+                               W_GiveWeapon (player, WEP_MINSTANEX, item.netname);
                        if (item.ammo_cells)
-                       {
-                               pickedup = TRUE;
-                               // play some cool sounds ;)
-                               if (clienttype(player) == CLIENTTYPE_REAL)
-                               {
-                                       if(player.health <= 5)
-                                               AnnounceTo(player, "lastsecond");
-                                       else if(player.health < 50)
-                                               AnnounceTo(player, "narrowly");
-                               }
-                               // sound not available
-                               // else if(item.items == IT_CELLS)
-                               //      AnnounceTo(player, "ammo");
-
-                               if (item.weapons & WEPBIT_MINSTANEX)
-                                       W_GiveWeapon (player, WEP_MINSTANEX, item.netname);
-                               if (item.ammo_cells)
-                                       player.ammo_cells = bound(player.ammo_cells, 999, player.ammo_cells + autocvar_g_minstagib_ammo_drop);
-                               player.health = 100;
-                       }
+                               player.ammo_cells = bound(player.ammo_cells, 999, player.ammo_cells + autocvar_g_minstagib_ammo_drop);
+                       player.health = 100;
+               }
 
-                       // extralife powerup
-                       if (item.max_health)
-                       {
-                               pickedup = TRUE;
-                               // sound not available
-                               // AnnounceTo(player, "_lives");
-                               player.armorvalue = bound(player.armorvalue, 999, player.armorvalue + autocvar_g_minstagib_extralives);
-                               sprint(player, "^3You picked up some extra lives\n");
-                       }
+               if((it = (item.items - (item.items & player.items)) & IT_PICKUPMASK))
+               {
+                       pickedup = TRUE;
+                       player.items |= it;
+                       sprint (player, strcat("You got the ^2", item.netname, "\n"));
+               }
 
-                       // invis powerup
-                       if (item.strength_finished)
-                       {
-                               pickedup = TRUE;
-                               // sound not available
-                               // AnnounceTo(player, "invisible");
-                               player.strength_finished = max(player.strength_finished, time) + autocvar_g_balance_powerup_strength_time;
-                       }
+               // extralife powerup
+               if (item.max_health)
+               {
+                       pickedup = TRUE;
+                       // sound not available
+                       // AnnounceTo(player, "_lives");
+                       player.armorvalue = bound(player.armorvalue, 999, player.armorvalue + autocvar_g_minstagib_extralives);
+                       sprint(player, "^3You picked up some extra lives\n");
+               }
 
-                       // speed powerup
-                       if (item.invincible_finished)
-                       {
-                               pickedup = TRUE;
-                               // sound not available
-                               // AnnounceTo(player, "speed");
-                               player.invincible_finished = max(player.invincible_finished, time) + autocvar_g_balance_powerup_strength_time;
-                       }
+               // invis powerup
+               if (item.strength_finished)
+               {
+                       pickedup = TRUE;
+                       // sound not available
+                       // AnnounceTo(player, "invisible");
+                       player.strength_finished = max(player.strength_finished, time) + autocvar_g_balance_powerup_strength_time;
+               }
+
+               // speed powerup
+               if (item.invincible_finished)
+               {
+                       pickedup = TRUE;
+                       // sound not available
+                       // AnnounceTo(player, "speed");
+                       player.invincible_finished = max(player.invincible_finished, time) + autocvar_g_balance_powerup_strength_time;
                }
        }
        else
@@ -375,43 +431,16 @@ float Item_GiveTo(entity item, entity player)
                if not(player.weapons & W_WeaponBit(player.switchweapon))
                        _switchweapon = TRUE;
 
-               if(item.spawnshieldtime)
-               {
-                       if (item.ammo_shells)
-                       if ((player.ammo_shells < g_pickup_shells_max) || item.pickup_anyway)
-                       {
-                               pickedup = TRUE;
-                               player.ammo_shells = bound(player.ammo_shells, g_pickup_shells_max, player.ammo_shells + item.ammo_shells);
-                       }
-                       if (item.ammo_nails)
-                       if ((player.ammo_nails < g_pickup_nails_max) || item.pickup_anyway)
-                       {
-                               pickedup = TRUE;
-                               player.ammo_nails = bound(player.ammo_nails, g_pickup_nails_max, player.ammo_nails + item.ammo_nails);
-                       }
-                       if (item.ammo_rockets)
-                       if ((player.ammo_rockets < g_pickup_rockets_max) || item.pickup_anyway)
-                       {
-                               pickedup = TRUE;
-                               player.ammo_rockets = bound(player.ammo_rockets, g_pickup_rockets_max, player.ammo_rockets + item.ammo_rockets);
-                       }
-                       if (item.ammo_cells)
-                       if ((player.ammo_cells < g_pickup_cells_max) || item.pickup_anyway)
-                       {
-                               pickedup = TRUE;
-                               player.ammo_cells = bound(player.ammo_cells, g_pickup_cells_max, player.ammo_cells + item.ammo_cells);
-                       }
-                       if (item.ammo_fuel)
-                       if ((player.ammo_fuel < g_pickup_fuel_max) || item.pickup_anyway)
-                       {
-                               pickedup = TRUE;
-                               player.ammo_fuel = bound(player.ammo_fuel, g_pickup_fuel_max, player.ammo_fuel + item.ammo_fuel);
-                               player.pauserotfuel_finished = max(player.pauserotfuel_finished, time + autocvar_g_balance_pause_fuel_rot);
-                       }
-               }
+               pickedup |= Item_GiveAmmoTo(item, player, ammo_fuel, g_pickup_fuel_max, ITEM_MODE_FUEL);
+               pickedup |= Item_GiveAmmoTo(item, player, ammo_shells, g_pickup_shells_max, ITEM_MODE_NONE);
+               pickedup |= Item_GiveAmmoTo(item, player, ammo_nails, g_pickup_nails_max, ITEM_MODE_NONE);
+               pickedup |= Item_GiveAmmoTo(item, player, ammo_rockets, g_pickup_rockets_max, ITEM_MODE_NONE);
+               pickedup |= Item_GiveAmmoTo(item, player, ammo_cells, g_pickup_cells_max, ITEM_MODE_NONE);
+               pickedup |= Item_GiveAmmoTo(item, player, health, item.max_health, ITEM_MODE_HEALTH);
+               pickedup |= Item_GiveAmmoTo(item, player, armorvalue, item.max_armorvalue, ITEM_MODE_ARMOR);
 
                if (item.flags & FL_WEAPON)
-               if ((it = item.weapons - (item.weapons & player.weapons)) || (g_pickup_weapons_anyway))
+               if ((it = item.weapons - (item.weapons & player.weapons)) || (item.spawnshieldtime && g_pickup_weapons_anyway))
                {
                        pickedup = TRUE;
                        for(i = WEP_FIRST; i <= WEP_LAST; ++i)
@@ -429,33 +458,20 @@ float Item_GiveTo(entity item, entity player)
                        sprint (player, strcat("You got the ^2", item.netname, "\n"));
                }
 
-               if(item.spawnshieldtime)
+               if (item.strength_finished)
                {
-                       if (item.strength_finished)
-                       {
-                               pickedup = TRUE;
-                               player.strength_finished = max(player.strength_finished, time) + autocvar_g_balance_powerup_strength_time;
-                       }
-                       if (item.invincible_finished)
-                       {
-                               pickedup = TRUE;
-                               player.invincible_finished = max(player.invincible_finished, time) + autocvar_g_balance_powerup_invincible_time;
-                       }
-
-                       if (item.health)
-                       if ((player.health < item.max_health) || item.pickup_anyway)
-                       {
-                               pickedup = TRUE;
-                               player.health = bound(player.health, item.max_health, player.health + item.health);
-                               player.pauserothealth_finished = max(player.pauserothealth_finished, time + autocvar_g_balance_pause_health_rot);
-                       }
-                       if (item.armorvalue)
-                       if ((player.armorvalue < item.max_armorvalue) || item.pickup_anyway)
-                       {
-                               pickedup = TRUE;
-                               player.armorvalue = bound(player.armorvalue, item.max_armorvalue, player.armorvalue + item.armorvalue);
-                               player.pauserotarmor_finished = max(player.pauserotarmor_finished, time + autocvar_g_balance_pause_armor_rot);
-                       }
+                       pickedup = TRUE;
+                       player.strength_finished = max(player.strength_finished, time) + item.strength_finished;
+               }
+               if (item.invincible_finished)
+               {
+                       pickedup = TRUE;
+                       player.invincible_finished = max(player.invincible_finished, time) + item.invincible_finished;
+               }
+               if (item.superweapons_finished)
+               {
+                       pickedup = TRUE;
+                       player.superweapons_finished = max(player.superweapons_finished, time) + item.superweapons_finished;
                }
        }
 
@@ -526,6 +542,17 @@ void Item_Touch (void)
        }
 }
 
+void Item_Reset()
+{
+       Item_Show(self, !self.state);
+       setorigin (self, self.origin);
+       self.think = SUB_Null;
+       self.nextthink = 0;
+
+       if((self.flags & FL_POWERUP) | (self.weapons & WEPBIT_SUPERWEAPONS)) // do not spawn powerups initially!
+               Item_ScheduleInitialRespawn(self);
+}
+
 void Item_FindTeam()
 {
        entity head, e;
@@ -552,22 +579,10 @@ void Item_FindTeam()
                        head.effects &~= EF_NODRAW;
                }
 
-               if(e.flags & FL_POWERUP) // do not spawn powerups initially!
-                       Item_ScheduleInitialRespawn(e);
+               Item_Reset();
        }
 }
 
-void Item_Reset()
-{
-       Item_Show(self, !self.state);
-       setorigin (self, self.origin);
-       self.think = SUB_Null;
-       self.nextthink = 0;
-
-       if(self.flags & FL_POWERUP) // do not spawn powerups initially!
-               Item_ScheduleInitialRespawn(self);
-}
-
 // Savage: used for item garbage-collection
 // TODO: perhaps nice special effect?
 void RemoveItem(void)
@@ -698,6 +713,7 @@ void StartItem (string itemmodel, string pickupsound, float defaultrespawntime,
 
        self.items = itemid;
        self.weapons = weaponid;
+       self.flags = FL_ITEM | itemflags;
 
        // is it a dropped weapon?
        if (self.classname == "droppedweapon")
@@ -733,6 +749,11 @@ void StartItem (string itemmodel, string pickupsound, float defaultrespawntime,
                        return;
                }
 
+               if(self.model != "")
+                       itemmodel = self.model;
+               if(self.item_pickupsound != "")
+                       pickupsound = self.item_pickupsound;
+
                self.reset = Item_Reset;
                // it's a level item
                if(self.spawnflags & 1)
@@ -807,6 +828,10 @@ void StartItem (string itemmodel, string pickupsound, float defaultrespawntime,
        self.bot_pickupbasevalue = pickupbasevalue;
        self.mdl = itemmodel;
        self.item_pickupsound = pickupsound;
+       if(self.weapons)
+               self.weapon = WEP_FIRST + log2of(lowestbit(self.weapons));
+       else
+               self.weapon = 0;
        // let mappers override respawntime
        if(!self.respawntime) // both set
        {
@@ -814,7 +839,6 @@ void StartItem (string itemmodel, string pickupsound, float defaultrespawntime,
                self.respawntimejitter = defaultrespawntimejitter;
        }
        self.netname = itemname;
-       self.flags = FL_ITEM | itemflags;
        self.touch = Item_Touch;
        setmodel (self, self.mdl); // precision set below
        self.effects |= EF_LOWPRECISION;
@@ -841,8 +865,8 @@ void StartItem (string itemmodel, string pickupsound, float defaultrespawntime,
                self.effects = self.effects | EF_NODRAW; // marker for item team search
                InitializeEntity(self, Item_FindTeam, INITPRIO_FINDTARGET);
        }
-       else if(self.flags & FL_POWERUP) // do not spawn powerups initially!
-               Item_ScheduleInitialRespawn(self);
+       else
+               Item_Reset();
 }
 
 /* replace items in minstagib
@@ -858,7 +882,7 @@ void minstagib_items (float itemid)
        // replace rocket launchers and nex guns with ammo cells
        if (itemid == IT_CELLS)
        {
-               self.ammo_cells = 1;
+               self.ammo_cells = autocvar_g_minstagib_ammo_drop;
                StartItem ("models/items/a_cells.md3",
                        "misc/itempickup.wav", 45, 0,
                        "MinstaNex Ammo", IT_CELLS, 0, 0, generic_pickupevalfunc, 100);
@@ -877,7 +901,8 @@ void minstagib_items (float itemid)
        // replace with invis
        if (itemid == IT_STRENGTH)
        {
-               self.strength_finished = 30;
+               if(!self.strength_finished)
+                       self.strength_finished = autocvar_g_balance_powerup_strength_time;
                StartItem ("models/items/g_strength.md3",
                        "misc/powerup.wav", g_pickup_respawntime_powerup, g_pickup_respawntimejitter_powerup,
                        "Invisibility", IT_STRENGTH, 0, FL_POWERUP, generic_pickupevalfunc, BOT_PICKUP_RATING_MID);
@@ -893,7 +918,8 @@ void minstagib_items (float itemid)
        // replace with speed
        if (itemid == IT_INVINCIBLE)
        {
-               self.invincible_finished = 30;
+               if(!self.invincible_finished)
+                       self.invincible_finished = autocvar_g_balance_powerup_invincible_time;
                StartItem ("models/items/g_invincible.md3",
                        "misc/powerup_shield.wav", g_pickup_respawntime_powerup, g_pickup_respawntimejitter_powerup,
                        "Speed", IT_INVINCIBLE, 0, FL_POWERUP, generic_pickupevalfunc, BOT_PICKUP_RATING_MID);
@@ -918,23 +944,6 @@ void weapon_defaultspawnfunc(float wpn)
        entity oldself;
        float i, j;
 
-       // set the respawntime in advance (so replaced weapons can copy it)
-
-       if(!self.respawntime)
-       {
-               e = get_weaponinfo(wpn);
-               if(e.items == IT_SUPERWEAPON)
-               {
-                       self.respawntime = g_pickup_respawntime_powerup;
-                       self.respawntimejitter = g_pickup_respawntimejitter_powerup;
-               }
-               else
-               {
-                       self.respawntime = g_pickup_respawntime_weapon;
-                       self.respawntimejitter = g_pickup_respawntimejitter_weapon;
-               }
-       }
-
        if(self.classname != "droppedweapon" && self.classname != "replacedweapon")
        {
                e = get_weaponinfo(wpn);
@@ -1000,7 +1009,25 @@ void weapon_defaultspawnfunc(float wpn)
 
        e = get_weaponinfo(wpn);
 
-       if(e.items && e.items != IT_SUPERWEAPON)
+       if(!self.respawntime)
+       {
+               if(e.weapons & WEPBIT_SUPERWEAPONS)
+               {
+                       self.respawntime = g_pickup_respawntime_superweapon;
+                       self.respawntimejitter = g_pickup_respawntimejitter_superweapon;
+               }
+               else
+               {
+                       self.respawntime = g_pickup_respawntime_weapon;
+                       self.respawntimejitter = g_pickup_respawntimejitter_weapon;
+               }
+       }
+
+       if(e.weapons & WEPBIT_SUPERWEAPONS)
+               if(!self.superweapons_finished)
+                       self.superweapons_finished = autocvar_g_balance_superweapons_time;
+
+       if(e.items)
        {
                for(i = 0, j = 1; i < 24; ++i, j *= 2)
                {
@@ -1012,10 +1039,10 @@ void weapon_defaultspawnfunc(float wpn)
                        }
                }
        }
-       else
-       {
+
+       // no weapon-stay on superweapons
+       if(self.weapons & WEPBIT_SUPERWEAPONS)
                self.flags |= FL_NO_WEAPON_STAY;
-       }
 
        // weapon stay isn't supported for teamed weapons
        if(self.team)
@@ -1232,7 +1259,8 @@ void spawnfunc_item_strength (void) {
                minstagib_items(IT_STRENGTH);
        } else {
                precache_sound("weapons/strength_fire.wav");
-               self.strength_finished = 30;
+               if(!self.strength_finished)
+                       self.strength_finished = autocvar_g_balance_powerup_strength_time;
                StartItem ("models/items/g_strength.md3", "misc/powerup.wav", g_pickup_respawntime_powerup, g_pickup_respawntimejitter_powerup, "Strength Powerup", IT_STRENGTH, 0, FL_POWERUP, generic_pickupevalfunc, 100000);
        }
 }
@@ -1241,7 +1269,8 @@ void spawnfunc_item_invincible (void) {
        if(g_minstagib) {
                minstagib_items(IT_INVINCIBLE);
        } else {
-               self.invincible_finished = 30;
+               if(!self.invincible_finished)
+                       self.invincible_finished = autocvar_g_balance_powerup_invincible_time;
                StartItem ("models/items/g_invincible.md3", "misc/powerup_shield.wav", g_pickup_respawntime_powerup, g_pickup_respawntimejitter_powerup, "Shield", IT_INVINCIBLE, 0, FL_POWERUP, generic_pickupevalfunc, 100000);
        }
 }
@@ -1294,6 +1323,8 @@ void spawnfunc_target_items (void)
                self.strength_finished = autocvar_g_balance_powerup_strength_time;
        if(!self.invincible_finished)
                self.invincible_finished = autocvar_g_balance_powerup_invincible_time;
+       if(!self.superweapons_finished)
+               self.superweapons_finished = autocvar_g_balance_superweapons_time;
 
        precache_sound("misc/itempickup.wav");
        precache_sound("misc/megahealth.wav");
@@ -1316,6 +1347,7 @@ void spawnfunc_target_items (void)
                        else if(argv(i) == "unlimited_superweapons") self.items |= IT_UNLIMITED_SUPERWEAPONS;
                        else if(argv(i) == "strength")               self.items |= IT_STRENGTH;
                        else if(argv(i) == "invincible")             self.items |= IT_INVINCIBLE;
+                       else if(argv(i) == "superweapons")           self.items |= IT_SUPERWEAPON;
                        else if(argv(i) == "jetpack")                self.items |= IT_JETPACK;
                        else if(argv(i) == "fuel_regen")             self.items |= IT_FUEL_REGEN;
                        else
@@ -1363,6 +1395,7 @@ void spawnfunc_target_items (void)
                self.netname = sprintf("%s %s%d %s", self.netname, itemprefix, !!(self.items & IT_UNLIMITED_SUPERWEAPONS), "unlimited_superweapons");
                self.netname = sprintf("%s %s%d %s", self.netname, valueprefix, self.strength_finished * !!(self.items & IT_STRENGTH), "strength");
                self.netname = sprintf("%s %s%d %s", self.netname, valueprefix, self.invincible_finished * !!(self.items & IT_INVINCIBLE), "invincible");
+               self.netname = sprintf("%s %s%d %s", self.netname, valueprefix, self.superweapons_finished * !!(self.items & IT_SUPERWEAPON), "superweapons");
                self.netname = sprintf("%s %s%d %s", self.netname, itemprefix, !!(self.items & IT_JETPACK), "jetpack");
                self.netname = sprintf("%s %s%d %s", self.netname, itemprefix, !!(self.items & IT_FUEL_REGEN), "fuel_regen");
                if(self.ammo_shells != 0) self.netname = sprintf("%s %s%d %s", self.netname, valueprefix, max(0, self.ammo_shells), "shells");
@@ -1541,11 +1574,13 @@ 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);
        
        PREGIVE(e, items);
        PREGIVE(e, weapons);
        PREGIVE(e, strength_finished);
        PREGIVE(e, invincible_finished);
+       PREGIVE(e, superweapons_finished);
        PREGIVE(e, ammo_nails);
        PREGIVE(e, ammo_cells);
        PREGIVE(e, ammo_shells);
@@ -1583,8 +1618,9 @@ float GiveItems(entity e, float beginarg, float endarg)
                                continue;
                        case "ALL":
                                got += GiveBit(e, items, IT_FUEL_REGEN, op, val);
-                               got += GiveValue(e, strength_finished, op, time);
-                               got += GiveValue(e, invincible_finished, op, time);
+                               got += GiveValue(e, strength_finished, op, val);
+                               got += GiveValue(e, invincible_finished, op, val);
+                               got += GiveValue(e, superweapons_finished, op, val);
                                got += GiveBit(e, items, IT_UNLIMITED_AMMO, op, val);
                        case "all":
                                got += GiveBit(e, items, IT_JETPACK, op, val);
@@ -1625,6 +1661,9 @@ float GiveItems(entity e, float beginarg, float endarg)
                        case "invincible":
                                got += GiveValue(e, invincible_finished, op, val);
                                break;
+                       case "superweapons":
+                               got += GiveValue(e, superweapons_finished, op, val);
+                               break;
                        case "cells":
                                got += GiveValue(e, ammo_cells, op, val);
                                break;
@@ -1690,6 +1729,10 @@ float GiveItems(entity e, float beginarg, float endarg)
        POSTGIVE_VALUE_ROT(e, armorvalue, 1, pauserotarmor_finished, autocvar_g_balance_pause_armor_rot, pauseregen_finished, autocvar_g_balance_pause_health_regen, "misc/armor25.wav", string_null);
        POSTGIVE_VALUE_ROT(e, health, 1, pauserothealth_finished, autocvar_g_balance_pause_health_rot, pauseregen_finished, autocvar_g_balance_pause_health_regen, "misc/megahealth.wav", string_null);
 
+       if(e.superweapons_finished <= 0)
+               if(self.weapons & WEPBIT_SUPERWEAPONS)
+                       e.superweapons_finished = autocvar_g_balance_superweapons_time;
+
        if (g_minstagib)
        {
                e.health = bound(0, e.health, 100);
@@ -1704,6 +1747,10 @@ float GiveItems(entity e, float beginarg, float endarg)
                e.invincible_finished = 0;
        else
                e.invincible_finished += time;
+       if(e.superweapons_finished <= 0)
+               e.superweapons_finished = 0;
+       else
+               e.superweapons_finished += time;
 
        if not(e.weapons & W_WeaponBit(e.switchweapon))
                _switchweapon = TRUE;