]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/server/t_items.qc
Merge branch 'master' into Mario/vaporizer_damage
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / t_items.qc
index 4455d3fb46a3128ecf541c8d4558286341eb8a4e..5d392fd84a24c8fc64a025fc4d2f1ae0aa2c2f4e 100644 (file)
@@ -1,3 +1,32 @@
+#include "t_items.qh"
+
+#include "../common/items/all.qc"
+
+#if defined(SVQC)
+    #include "_all.qh"
+
+    #include "bot/bot.qh"
+    #include "bot/waypoints.qh"
+
+    #include "mutators/mutators_include.qh"
+
+    #include "weapons/common.qh"
+    #include "weapons/selection.qh"
+    #include "weapons/weaponsystem.qh"
+
+    #include "../common/constants.qh"
+    #include "../common/deathtypes.qh"
+    #include "../common/notifications.qh"
+       #include "../common/triggers/subs.qh"
+    #include "../common/util.qh"
+
+    #include "../common/monsters/all.qh"
+
+    #include "../common/weapons/all.qh"
+
+    #include "../warpzonelib/util_server.qh"
+#endif
+
 #ifdef CSQC
 void ItemDraw()
 {
@@ -46,9 +75,29 @@ void ItemDrawSimple()
     }
 }
 
+void Item_PreDraw()
+{
+       vector org;
+       float alph;
+       org = getpropertyvec(VF_ORIGIN);
+       if(!checkpvs(org, self)) // this makes sense as long as we don't support recursive warpzones
+               alph = 0;
+       else if(self.fade_start)
+               alph = bound(0, (self.fade_end - vlen(org - self.origin - 0.5 * (self.mins + self.maxs))) / (self.fade_end - self.fade_start), 1);
+       else
+               alph = 1;
+       //printf("%v <-> %v\n", view_origin, self.origin + 0.5 * (self.mins + self.maxs));
+       if(self.ItemStatus & ITS_AVAILABLE)
+               self.alpha = alph;
+       if(alph <= 0)
+               self.drawmask = 0;
+       else
+               self.drawmask = MASK_NORMAL;
+}
+
 void ItemRead(float _IsNew)
 {
-    float sf = ReadByte();
+    int sf = ReadByte();
 
     if(sf & ISF_LOCATION)
     {
@@ -61,21 +110,16 @@ void ItemRead(float _IsNew)
 
     if(sf & ISF_ANGLES)
     {
-        self.angles_x = ReadCoord();
-        self.angles_y = ReadCoord();
-        self.angles_z = ReadCoord();
+        self.angles_x = ReadAngle();
+        self.angles_y = ReadAngle();
+        self.angles_z = ReadAngle();
         self.move_angles = self.angles;
     }
 
     if(sf & ISF_SIZE)
     {
-        self.mins_x = ReadCoord();
-        self.mins_y = ReadCoord();
-        self.mins_z = ReadCoord();
-        self.maxs_x = ReadCoord();
-        self.maxs_y = ReadCoord();
-        self.maxs_z = ReadCoord();
-        setsize(self, self.mins, self.maxs);
+        float use_bigsize = ReadByte();
+        setsize(self, '-16 -16 0', (use_bigsize) ? '16 16 48' : '16 16 32');
     }
 
     if(sf & ISF_STATUS) // need to read/write status frist so model can handle simple, fb etc.
@@ -121,9 +165,14 @@ void ItemRead(float _IsNew)
     if(sf & ISF_MODEL)
     {
         self.drawmask  = MASK_NORMAL;
-        self.movetype  = MOVETYPE_TOSS;
+               self.move_movetype = self.movetype = MOVETYPE_TOSS;
         self.draw       = ItemDraw;
 
+        self.fade_end = ReadShort();
+        self.fade_start = ReadShort();
+        if(self.fade_start && !autocvar_cl_items_nofade)
+               self.predraw = Item_PreDraw;
+
         if(self.mdl)
             strunzone(self.mdl);
 
@@ -135,20 +184,18 @@ void ItemRead(float _IsNew)
             string _fn2 = substring(_fn, 0 , strlen(_fn) -4);
             self.draw = ItemDrawSimple;
 
-
-
             if(fexists(sprintf("%s%s.md3", _fn2, autocvar_cl_simpleitems_postfix)))
                 self.mdl = strzone(sprintf("%s%s.md3", _fn2, autocvar_cl_simpleitems_postfix));
             else if(fexists(sprintf("%s%s.dpm", _fn2, autocvar_cl_simpleitems_postfix)))
                 self.mdl = strzone(sprintf("%s%s.dpm", _fn2, autocvar_cl_simpleitems_postfix));
             else if(fexists(sprintf("%s%s.iqm", _fn2, autocvar_cl_simpleitems_postfix)))
                 self.mdl = strzone(sprintf("%s%s.iqm", _fn2, autocvar_cl_simpleitems_postfix));
-            else if(fexists(sprintf("%s%s.obj", _fn2, autocvar_cl_simpleitems_postfix)))
-                self.mdl = strzone(sprintf("%s%s.obj", _fn2, autocvar_cl_simpleitems_postfix));
+            else if(fexists(sprintf("%s%s.mdl", _fn2, autocvar_cl_simpleitems_postfix)))
+                self.mdl = strzone(sprintf("%s%s.mdl", _fn2, autocvar_cl_simpleitems_postfix));
             else
             {
                 self.draw = ItemDraw;
-                dprint("Simple item requested for ", _fn, " but no model exsist for it\n");
+                LOG_TRACE("Simple item requested for ", _fn, " but no model exists for it\n");
             }
         }
 
@@ -157,7 +204,7 @@ void ItemRead(float _IsNew)
 
 
         if(self.mdl == "")
-            dprint("^1WARNING!^7 self.mdl is unset for item ", self.classname, " tell tZork aboute this!\n");
+            LOG_TRACE("^1WARNING!^7 self.mdl is unset for item ", self.classname, " tell tZork aboute this!\n");
 
         precache_model(self.mdl);
         setmodel(self, self.mdl);
@@ -199,65 +246,62 @@ void ItemRead(float _IsNew)
 #endif
 
 #ifdef SVQC
-float ItemSend(entity to, float sf)
+bool ItemSend(entity to, int sf)
 {
-    if(self.gravity)
-        sf |= ISF_DROP;
-    else
-        sf &= ~ISF_DROP;
+       if(self.gravity)
+               sf |= ISF_DROP;
+       else
+               sf &= ~ISF_DROP;
 
        WriteByte(MSG_ENTITY, ENT_CLIENT_ITEM);
        WriteByte(MSG_ENTITY, sf);
 
        //WriteByte(MSG_ENTITY, self.cnt);
-    if(sf & ISF_LOCATION)
-    {
-        WriteCoord(MSG_ENTITY, self.origin_x);
-        WriteCoord(MSG_ENTITY, self.origin_y);
-        WriteCoord(MSG_ENTITY, self.origin_z);
-    }
+       if(sf & ISF_LOCATION)
+       {
+               WriteCoord(MSG_ENTITY, self.origin.x);
+               WriteCoord(MSG_ENTITY, self.origin.y);
+               WriteCoord(MSG_ENTITY, self.origin.z);
+       }
 
-    if(sf & ISF_ANGLES)
-    {
-        WriteCoord(MSG_ENTITY, self.angles_x);
-        WriteCoord(MSG_ENTITY, self.angles_y);
-        WriteCoord(MSG_ENTITY, self.angles_z);
-    }
+       if(sf & ISF_ANGLES)
+       {
+               WriteAngle(MSG_ENTITY, self.angles_x);
+               WriteAngle(MSG_ENTITY, self.angles_y);
+               WriteAngle(MSG_ENTITY, self.angles_z);
+       }
 
-    if(sf & ISF_SIZE)
-    {
-        WriteCoord(MSG_ENTITY, self.mins_x);
-        WriteCoord(MSG_ENTITY, self.mins_y);
-        WriteCoord(MSG_ENTITY, self.mins_z);
-        WriteCoord(MSG_ENTITY, self.maxs_x);
-        WriteCoord(MSG_ENTITY, self.maxs_y);
-        WriteCoord(MSG_ENTITY, self.maxs_z);
-    }
+       if(sf & ISF_SIZE)
+       {
+               WriteByte(MSG_ENTITY, ((self.flags & FL_POWERUP) || self.health || self.armorvalue));
+       }
 
-    if(sf & ISF_STATUS)
-        WriteByte(MSG_ENTITY, self.ItemStatus);
+       if(sf & ISF_STATUS)
+               WriteByte(MSG_ENTITY, self.ItemStatus);
 
-    if(sf & ISF_MODEL)
-    {
+       if(sf & ISF_MODEL)
+       {
+               WriteShort(MSG_ENTITY, self.fade_end);
+               WriteShort(MSG_ENTITY, self.fade_start);
 
-        if(self.mdl == "")
-            dprint("^1WARNING!^7 self.mdl is unset for item ", self.classname, "exspect a crash just aboute now\n");
+               if(self.mdl == "")
+                       LOG_TRACE("^1WARNING!^7 self.mdl is unset for item ", self.classname, "exspect a crash just aboute now\n");
 
-        WriteString(MSG_ENTITY, self.mdl);
-    }
+               WriteString(MSG_ENTITY, self.mdl);
+       }
 
 
-    if(sf & ISF_COLORMAP)
-        WriteShort(MSG_ENTITY, self.colormap);
+       if(sf & ISF_COLORMAP)
+               WriteShort(MSG_ENTITY, self.colormap);
 
-    if(sf & ISF_DROP)
-    {
-        WriteCoord(MSG_ENTITY, self.velocity_x);
-        WriteCoord(MSG_ENTITY, self.velocity_y);
-        WriteCoord(MSG_ENTITY, self.velocity_z);
-    }
+       if(sf & ISF_DROP)
+       {
+               WriteCoord(MSG_ENTITY, self.velocity.x);
+               WriteCoord(MSG_ENTITY, self.velocity.y);
+               WriteCoord(MSG_ENTITY, self.velocity.z);
+       }
 
-    return TRUE;
+       return true;
 }
 
 void ItemUpdate(entity item)
@@ -270,34 +314,34 @@ float have_pickup_item(void)
        if(self.flags & FL_POWERUP)
        {
                if(autocvar_g_powerups > 0)
-                       return TRUE;
+                       return true;
                if(autocvar_g_powerups == 0)
-                       return FALSE;
+                       return false;
        }
        else
        {
                if(autocvar_g_pickup_items > 0)
-                       return TRUE;
+                       return true;
                if(autocvar_g_pickup_items == 0)
-                       return FALSE;
+                       return false;
                if(g_weaponarena)
                        if(self.weapons || (self.items & IT_AMMO)) // no item or ammo pickups in weaponarena
-                               return FALSE;
+                               return false;
        }
-       return TRUE;
+       return true;
 }
 
 /*
 float Item_Customize()
 {
        if(self.spawnshieldtime)
-               return TRUE;
+               return true;
        if(self.weapons & ~other.weapons)
        {
                self.colormod = '0 0 0';
                self.glowmod = self.colormod;
                self.alpha = 0.5 + 0.5 * g_ghost_items; // halfway more alpha
-               return TRUE;
+               return true;
        }
        else
        {
@@ -306,10 +350,10 @@ float Item_Customize()
                        self.colormod = stov(autocvar_g_ghost_items_color);
                        self.glowmod = self.colormod;
                        self.alpha = g_ghost_items;
-                       return TRUE;
+                       return true;
                }
                else
-                       return FALSE;
+                       return false;
        }
 }
 */
@@ -353,22 +397,22 @@ void Item_Show (entity e, float mode)
                e.ItemStatus &= ~ITS_AVAILABLE;
        }
 
-       if (e.items & IT_STRENGTH || e.items & IT_INVINCIBLE)
-           e.ItemStatus |= ITS_POWERUP;
+       if (e.items & ITEM_Strength.m_itemid || e.items & ITEM_Shield.m_itemid)
+               e.ItemStatus |= ITS_POWERUP;
 
        if (autocvar_g_nodepthtestitems)
                e.effects |= EF_NODEPTHTEST;
 
 
-    if (autocvar_g_fullbrightitems)
+       if (autocvar_g_fullbrightitems)
                e.ItemStatus |= ITS_ALLOWFB;
 
        if (autocvar_sv_simple_items)
-        e.ItemStatus |= ITS_ALLOWSI;
+               e.ItemStatus |= ITS_ALLOWSI;
 
        // relink entity (because solid may have changed)
        setorigin(e, e.origin);
-    e.SendFlags |= ISF_STATUS;
+       e.SendFlags |= ISF_STATUS;
 }
 
 void Item_Think()
@@ -381,23 +425,36 @@ void Item_Think()
        }
 }
 
+bool Item_ItemsTime_SpectatorOnly(GameItem it);
+bool Item_ItemsTime_Allow(GameItem it, WepSet _weapons);
+float Item_ItemsTime_UpdateTime(entity e, float t);
+void Item_ItemsTime_SetTime(entity e, float t);
+void Item_ItemsTime_SetTimesForAllPlayers();
+
 void Item_Respawn (void)
 {
        Item_Show(self, 1);
        // this is ugly...
-       if(self.items == IT_STRENGTH)
+       if(self.items == ITEM_Strength.m_itemid)
                sound (self, CH_TRIGGER, "misc/strength_respawn.wav", VOL_BASE, ATTEN_NORM);    // play respawn sound
-       else if(self.items == IT_INVINCIBLE)
+       else if(self.items == ITEM_Shield.m_itemid)
                sound (self, CH_TRIGGER, "misc/shield_respawn.wav", VOL_BASE, ATTEN_NORM);      // play respawn sound
        else
                sound (self, CH_TRIGGER, "misc/itemrespawn.wav", VOL_BASE, ATTEN_NORM); // play respawn sound
        setorigin (self, self.origin);
 
+    if (Item_ItemsTime_Allow(self.itemdef, self.weapons))
+       {
+               float t = Item_ItemsTime_UpdateTime(self, 0);
+               Item_ItemsTime_SetTime(self, t);
+               Item_ItemsTime_SetTimesForAllPlayers();
+       }
+
        self.think = Item_Think;
        self.nextthink = time;
-       
-       //pointparticles(particleeffectnum("item_respawn"), self.origin + self.mins_z * '0 0 1' + '0 0 48', '0 0 0', 1);
-       pointparticles(particleeffectnum("item_respawn"), self.origin + 0.5 * (self.mins + self.maxs), '0 0 0', 1);
+
+       //Send_Effect(EFFECT_ITEM_RESPAWN, self.origin + self.mins_z * '0 0 1' + '0 0 48', '0 0 0', 1);
+       Send_Effect(EFFECT_ITEM_RESPAWN, CENTER_OR_VIEWOFS(self), '0 0 0', 1);
 }
 
 void Item_RespawnCountdown (void)
@@ -414,48 +471,43 @@ void Item_RespawnCountdown (void)
                self.count += 1;
                if(self.count == 1)
                {
-                       string name;
-                       vector rgb = '1 0 1';
-                       name = string_null;
-                       switch(self.items)
-                       {
-                               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;
-                               case IT_STRENGTH:   name = "item-strength"; rgb = '0 0 1'; break;
-                               case IT_INVINCIBLE: name = "item-shield"; rgb = '1 0 1'; break;
-                       }
-                       item_name = name;
-                       item_color = rgb;
-                       MUTATOR_CALLHOOK(Item_RespawnCountdown);
-                       name = item_name;
-                       rgb = item_color;
-                       if(self.flags & FL_WEAPON)
-                       {
+                       MUTATOR_CALLHOOK(Item_RespawnCountdown, string_null, '0 0 0');
+                       int wpextra = 0;
+            entity e = self.itemdef;
+            if (e) wpextra = e.m_id;
+                       if (self.flags & FL_WEAPON) {
                                entity wi = get_weaponinfo(self.weapon);
-                               if(wi)
-                               {
-                                       name = wi.wpmodel;
-                                       rgb = '1 0 0';
-                               }
-                       }
-                       if(name)
-                       {
-                               WaypointSprite_Spawn(name, 0, 0, self, '0 0 64', world, 0, self, waypointsprite_attached, TRUE, RADARICON_POWERUP, rgb);
-                               if(self.waypointsprite_attached)
-                                       WaypointSprite_UpdateBuildFinished(self.waypointsprite_attached, time + ITEM_RESPAWN_TICKS);
-                       }
-                       else
-                       {
-                               print("Unknown powerup-marked item is wanting to respawn\n");
-                               localcmd(sprintf("prvm_edict server %d\n", num_for_edict(self)));
+                               if (wi) wpextra = wi.m_id;
                        }
+            entity wp = WaypointSprite_Spawn(WP_Item, 0, 0, self, '0 0 64', world, 0, self, waypointsprite_attached, true, RADARICON_POWERUP);
+            wp.wp_extra = wpextra;
+            if(self.waypointsprite_attached)
+            {
+                GameItem def = self.itemdef;
+                if (Item_ItemsTime_SpectatorOnly(def))
+                    WaypointSprite_UpdateRule(self.waypointsprite_attached, 0, SPRITERULE_SPECTATOR);
+                WaypointSprite_UpdateBuildFinished(self.waypointsprite_attached, time + ITEM_RESPAWN_TICKS);
+            }
                }
-               sound (self, CH_TRIGGER, "misc/itemrespawncountdown.wav", VOL_BASE, ATTEN_NORM);        // play respawn sound
+
                if(self.waypointsprite_attached)
                {
+                       entity e;
+                       entity it = self;
+                       self = self.waypointsprite_attached;
+                       FOR_EACH_REALCLIENT(e)
+                               if(self.waypointsprite_visible_for_player(e))
+                               {
+                                       msg_entity = e;
+                                       soundto(MSG_ONE, it, CH_TRIGGER, "misc/itemrespawncountdown.wav", VOL_BASE, ATTEN_NORM);        // play respawn sound
+                               }
+                       self = it;
+
                        WaypointSprite_Ping(self.waypointsprite_attached);
                        //WaypointSprite_UpdateHealth(self.waypointsprite_attached, self.count);
                }
+               else
+                       sound(self, CH_TRIGGER, "misc/itemrespawncountdown.wav", VOL_BASE, ATTEN_NORM); // play respawn sound
        }
 }
 
@@ -474,16 +526,21 @@ void Item_RespawnThink()
 
 void Item_ScheduleRespawnIn(entity e, float t)
 {
-       if((e.flags & FL_POWERUP) || (e.weapons & WEPSET_SUPERWEAPONS))
+       if (Item_ItemsTime_Allow(e.itemdef, e.weapons))
        {
                e.think = 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();
        }
        else
        {
                e.think = Item_RespawnThink;
                e.nextthink = time;
+               e.scheduledrespawntime = time + t;
                e.wait = time + t;
        }
 }
@@ -507,28 +564,28 @@ void Item_ScheduleInitialRespawn(entity e)
 
 float Item_GiveAmmoTo(entity item, entity player, .float ammotype, float ammomax, float mode)
 {
-       if (!item.ammotype)
-               return FALSE;
+       if (!item.(ammotype))
+               return false;
 
        if (item.spawnshieldtime)
        {
-               if ((player.ammotype < ammomax) || item.pickup_anyway)
+               if ((player.(ammotype) < ammomax) || item.pickup_anyway)
                {
-                       player.ammotype = bound(player.ammotype, ammomax, player.ammotype + item.ammotype);
+                       player.(ammotype) = bound(player.(ammotype), ammomax, player.(ammotype) + item.(ammotype));
                        goto YEAH;
                }
        }
        else if(g_weapon_stay == 2)
        {
-               float mi = min(item.ammotype, ammomax);
-               if (player.ammotype < mi)
+               float mi = min(item.(ammotype), ammomax);
+               if (player.(ammotype) < mi)
                {
-                       player.ammotype = mi;
+                       player.(ammotype) = mi;
                        goto YEAH;
                }
        }
 
-       return FALSE;
+       return false;
 
 :YEAH
        switch(mode)
@@ -545,7 +602,7 @@ float Item_GiveAmmoTo(entity item, entity player, .float ammotype, float ammomax
                default:
                        break;
        }
-       return TRUE;
+       return true;
 }
 
 float Item_GiveTo(entity item, entity player)
@@ -556,17 +613,17 @@ float Item_GiveTo(entity item, entity player)
        float i;
 
        // if nothing happens to player, just return without taking the item
-       pickedup = FALSE;
-       _switchweapon = FALSE;
+       pickedup = false;
+       _switchweapon = false;
        // in case the player has autoswitch enabled do the following:
        // if the player is using their best weapon before items are given, they
        // probably want to switch to an even better weapon after items are given
        if (player.autoswitch)
        if (player.switchweapon == w_getbestweapon(player))
-               _switchweapon = TRUE;
+               _switchweapon = true;
 
        if (!(player.weapons & WepSet_FromWeapon(player.switchweapon)))
-               _switchweapon = TRUE;
+               _switchweapon = true;
 
        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);
@@ -585,7 +642,7 @@ float Item_GiveTo(entity item, entity player)
 
                if (it || (item.spawnshieldtime && item.pickup_anyway))
                {
-                       pickedup = TRUE;
+                       pickedup = true;
                        for(i = WEP_FIRST; i <= WEP_LAST; ++i)
                        if(it & WepSet_FromWeapon(i))
                        {
@@ -597,24 +654,24 @@ float Item_GiveTo(entity item, entity player)
 
        if((it = (item.items - (item.items & player.items)) & IT_PICKUPMASK))
        {
-               pickedup = TRUE;
+               pickedup = true;
                player.items |= it;
                Send_Notification(NOTIF_ONE, player, MSG_INFO, INFO_ITEM_WEAPON_GOT, item.netname);
        }
 
        if (item.strength_finished)
        {
-               pickedup = TRUE;
+               pickedup = true;
                player.strength_finished = max(player.strength_finished, time) + item.strength_finished;
        }
        if (item.invincible_finished)
        {
-               pickedup = TRUE;
+               pickedup = true;
                player.invincible_finished = max(player.invincible_finished, time) + item.invincible_finished;
        }
        if (item.superweapons_finished)
        {
-               pickedup = TRUE;
+               pickedup = true;
                player.superweapons_finished = max(player.superweapons_finished, time) + item.superweapons_finished;
        }
 
@@ -622,11 +679,18 @@ float Item_GiveTo(entity item, entity player)
 
        // always eat teamed entities
        if(item.team)
-               pickedup = TRUE;
+               pickedup = true;
 
        if (!pickedup)
                return 0;
 
+       // crude hack to enforce switching weapons
+       if(g_cts && (item.flags & FL_WEAPON))
+       {
+               W_SwitchWeapon_Force(player, item.weapon);
+               return 1;
+       }
+
        if (_switchweapon)
                if (player.switchweapon != w_getbestweapon(player))
                        W_SwitchWeapon_Force(player, w_getbestweapon(player));
@@ -648,20 +712,15 @@ void Item_Touch (void)
                }
        }
 
-       if (!IS_PLAYER(other))
-               return;
-       if (other.frozen)
-               return;
-       if (other.deadflag)
-               return;
-       if (self.solid != SOLID_TRIGGER)
-               return;
-       if (self.owner == other)
-               return;
-       if (time < self.item_spawnshieldtime)
-               return;
+       if(!(other.flags & FL_PICKUPITEMS)
+       || other.frozen
+       || other.deadflag
+       || (self.solid != SOLID_TRIGGER)
+       || (self.owner == other)
+       || (time < self.item_spawnshieldtime)
+       ) { return;}
 
-       switch(MUTATOR_CALLHOOK(ItemTouch))
+       switch(MUTATOR_CALLHOOK(ItemTouch, self, other))
        {
                case MUT_ITEMTOUCH_RETURN: { return; }
                case MUT_ITEMTOUCH_PICKUP: { goto pickup; }
@@ -673,8 +732,9 @@ void Item_Touch (void)
                self.invincible_finished = max(0, self.invincible_finished - time);
                self.superweapons_finished = max(0, self.superweapons_finished - time);
        }
-
-       if(!Item_GiveTo(self, other))
+       entity it = self.itemdef;
+       bool gave = (it && it.instanceOfPickup) ? ITEM_HANDLE(Pickup, it, self, other) : Item_GiveTo(self, other);
+       if (!gave)
        {
                if (self.classname == "droppedweapon")
                {
@@ -690,14 +750,12 @@ void Item_Touch (void)
 
        other.last_pickup = time;
 
-       pointparticles(particleeffectnum("item_pickup"), self.origin, '0 0 0', 1);
+       Send_Effect(EFFECT_ITEM_PICKUP, CENTER_OR_VIEWOFS(self), '0 0 0', 1);
        sound (other, CH_TRIGGER, self.item_pickupsound, VOL_BASE, ATTEN_NORM);
 
        if (self.classname == "droppedweapon")
                remove (self);
-       else if (!self.spawnshieldtime)
-               return;
-       else
+       else if (self.spawnshieldtime)
        {
                if(self.team)
                {
@@ -705,6 +763,7 @@ void Item_Touch (void)
                        for(head = world; (head = findfloat(head, team, self.team)); )
                        {
                                if(head.flags & FL_ITEM)
+                               if(head.classname != "item_flag_team" && head.classname != "item_key_team")
                                {
                                        Item_Show(head, -1);
                                        RandomSelection_Add(head, 0, string_null, head.cnt, 0);
@@ -744,15 +803,19 @@ void Item_FindTeam()
        if(self.effects & EF_NODRAW)
        {
                // marker for item team search
-               dprint("Initializing item team ", ftos(self.team), "\n");
+               LOG_TRACE("Initializing item team ", ftos(self.team), "\n");
                RandomSelection_Init();
-               for(head = world; (head = findfloat(head, team, self.team)); ) if(head.flags & FL_ITEM)
+               for(head = world; (head = findfloat(head, team, self.team)); )
+               if(head.flags & FL_ITEM)
+               if(head.classname != "item_flag_team" && head.classname != "item_key_team")
                        RandomSelection_Add(head, 0, string_null, head.cnt, 0);
                e = RandomSelection_chosen_ent;
                e.state = 0;
                Item_Show(e, 1);
 
-               for(head = world; (head = findfloat(head, team, self.team)); ) if(head.flags & FL_ITEM)
+               for(head = world; (head = findfloat(head, team, self.team)); )
+               if(head.flags & FL_ITEM)
+               if(head.classname != "item_flag_team" && head.classname != "item_key_team")
                {
                        if(head != e)
                        {
@@ -771,6 +834,8 @@ void Item_FindTeam()
 // TODO: perhaps nice special effect?
 void RemoveItem(void)
 {
+       if(wasfreed(self) || !self) { return; }
+       Send_Effect(EFFECT_ITEM_PICKUP, CENTER_OR_VIEWOFS(self), '0 0 0', 1);
        remove(self);
 }
 
@@ -781,7 +846,7 @@ float generic_pickupevalfunc(entity player, entity item) {return item.bot_pickup
 
 float weapon_pickupevalfunc(entity player, entity item)
 {
-       float c, j, position;
+       float c;
 
        // See if I have it already
        if(item.weapons & ~player.weapons)
@@ -804,8 +869,8 @@ float weapon_pickupevalfunc(entity player, entity item)
        if( bot_custom_weapon && c )
        {
                // Find the highest position on any range
-               position = -1;
-               for(j = 0; j < WEP_LAST ; ++j){
+               int position = -1;
+               for (int j = 0; j < WEP_LAST ; ++j){
                        if(
                                        bot_weapons_far[j] == item.weapon ||
                                        bot_weapons_mid[j] == item.weapon ||
@@ -832,7 +897,7 @@ float weapon_pickupevalfunc(entity player, entity item)
 float commodity_pickupevalfunc(entity player, entity item)
 {
        float c, i;
-       float need_shells = FALSE, need_nails = FALSE, need_rockets = FALSE, need_cells = FALSE, need_plasma = FALSE, need_fuel = FALSE;
+       float need_shells = false, need_nails = false, need_rockets = false, need_cells = false, need_plasma = false, need_fuel = false;
        entity wi;
        c = 0;
 
@@ -844,18 +909,18 @@ float commodity_pickupevalfunc(entity player, entity item)
                if (!(player.weapons & WepSet_FromWeapon(i)))
                        continue;
 
-               if(wi.items & IT_SHELLS)
-                       need_shells = TRUE;
-               else if(wi.items & IT_NAILS)
-                       need_nails = TRUE;
-               else if(wi.items & IT_ROCKETS)
-                       need_rockets = TRUE;
-               else if(wi.items & IT_CELLS)
-                       need_cells = TRUE;
-               else if(wi.items & IT_PLASMA)
-                       need_plasma = TRUE;
-               else if(wi.items & IT_FUEL)
-                       need_fuel = TRUE;
+               if(wi.items & ITEM_Shells.m_itemid)
+                       need_shells = true;
+               else if(wi.items & ITEM_Bullets.m_itemid)
+                       need_nails = true;
+               else if(wi.items & ITEM_Rockets.m_itemid)
+                       need_rockets = true;
+               else if(wi.items & ITEM_Cells.m_itemid)
+                       need_cells = true;
+               else if(wi.items & ITEM_Plasma.m_itemid)
+                       need_plasma = true;
+               else if(wi.items & ITEM_JetpackFuel.m_itemid)
+                       need_fuel = true;
        }
 
        // TODO: figure out if the player even has the weapon this ammo is for?
@@ -895,7 +960,7 @@ float commodity_pickupevalfunc(entity player, entity item)
        return item.bot_pickupbasevalue * c;
 }
 
-void Item_Damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
+void Item_Damage(entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
 {
        if(ITEM_DAMAGE_NEEDKILL(deathtype))
                RemoveItem();
@@ -903,7 +968,7 @@ void Item_Damage(entity inflictor, entity attacker, float damage, float deathtyp
 
 void StartItem (string itemmodel, string pickupsound, float defaultrespawntime, float defaultrespawntimejitter, string itemname, float itemid, float weaponid, float itemflags, float(entity player, entity item) pickupevalfunc, float pickupbasevalue)
 {
-       startitem_failed = FALSE;
+       startitem_failed = false;
 
        if(self.model == "")
                self.model = itemmodel;
@@ -926,6 +991,12 @@ void StartItem (string itemmodel, string pickupsound, float defaultrespawntime,
        self.items = itemid;
        self.weapon = weaponid;
 
+       if(!self.fade_end)
+       {
+               self.fade_start = autocvar_g_items_mindist;
+               self.fade_end = autocvar_g_items_maxdist;
+       }
+
        if(weaponid)
                self.weapons = WepSet_FromWeapon(weaponid);
 
@@ -933,7 +1004,7 @@ void StartItem (string itemmodel, string pickupsound, float defaultrespawntime,
 
        if(MUTATOR_CALLHOOK(FilterItem)) // error means we do not want the item
        {
-               startitem_failed = TRUE;
+               startitem_failed = true;
                remove(self);
                return;
        }
@@ -973,7 +1044,7 @@ void StartItem (string itemmodel, string pickupsound, float defaultrespawntime,
                traceline(self.origin, self.origin, MOVE_NORMAL, self);
                if (trace_dpstartcontents & DPCONTENTS_NODROP)
                {
-                       startitem_failed = TRUE;
+                       startitem_failed = true;
                        remove(self);
                        return;
                }
@@ -982,11 +1053,14 @@ void StartItem (string itemmodel, string pickupsound, float defaultrespawntime,
        {
                if(!have_pickup_item())
                {
-                       startitem_failed = TRUE;
+                       startitem_failed = true;
                        remove (self);
                        return;
                }
 
+               if(self.angles != '0 0 0')
+                       self.SendFlags |= ISF_ANGLES;
+
                self.reset = Item_Reset;
                // it's a level item
                if(self.spawnflags & 1)
@@ -1005,8 +1079,8 @@ void StartItem (string itemmodel, string pickupsound, float defaultrespawntime,
                                setsize (self, '-16 -16 0', '16 16 48');
                        else
                                setsize (self, '-16 -16 0', '16 16 32');
-
-                       // note droptofloor returns FALSE if stuck/or would fall too far
+                       self.SendFlags |= ISF_SIZE;
+                       // note droptofloor returns false if stuck/or would fall too far
                        droptofloor();
                        waypoint_spawnforitem(self);
                }
@@ -1019,7 +1093,7 @@ void StartItem (string itemmodel, string pickupsound, float defaultrespawntime,
                {
                        // target_give not yet supported; maybe later
                        print("removed targeted ", self.classname, "\n");
-                       startitem_failed = TRUE;
+                       startitem_failed = true;
                        remove (self);
                        return;
                }
@@ -1033,12 +1107,12 @@ void StartItem (string itemmodel, string pickupsound, float defaultrespawntime,
                            // why not flags & fl_item?
                                if(otheritem.is_item)
                                {
-                                       dprint("XXX Found duplicated item: ", itemname, vtos(self.origin));
-                                       dprint(" vs ", otheritem.netname, vtos(otheritem.origin), "\n");
+                                       LOG_TRACE("XXX Found duplicated item: ", itemname, vtos(self.origin));
+                                       LOG_TRACE(" vs ", otheritem.netname, vtos(otheritem.origin), "\n");
                                        error("Mapper sucks.");
                                }
                        }
-                       self.is_item = TRUE;
+                       self.is_item = true;
                }
 
                weaponsInMap |= WepSet_FromWeapon(weaponid);
@@ -1047,18 +1121,20 @@ void StartItem (string itemmodel, string pickupsound, float defaultrespawntime,
                precache_sound (self.item_pickupsound);
 
                precache_sound ("misc/itemrespawncountdown.wav");
-               if(itemid == IT_STRENGTH)
+               if(itemid == ITEM_Strength.m_itemid)
                        precache_sound ("misc/strength_respawn.wav");
-               else if(itemid == IT_INVINCIBLE)
+               else if(itemid == ITEM_Shield.m_itemid)
                        precache_sound ("misc/shield_respawn.wav");
                else
                        precache_sound ("misc/itemrespawn.wav");
 
                if((itemflags & (FL_POWERUP | FL_WEAPON)) || (itemid & (IT_HEALTH | IT_ARMOR | IT_KEY1 | IT_KEY2)))
                        self.target = "###item###"; // for finding the nearest item using find()
+
+               Item_ItemsTime_SetTime(self, 0);
        }
 
-       self.bot_pickup = TRUE;
+       self.bot_pickup = true;
        self.bot_pickupevalfunc = pickupevalfunc;
        self.bot_pickupbasevalue = pickupbasevalue;
        self.mdl = self.model;
@@ -1068,29 +1144,31 @@ void StartItem (string itemmodel, string pickupsound, float defaultrespawntime,
        //self.effects |= EF_LOWPRECISION;
 
        if((itemflags & FL_POWERUP) || self.health || self.armorvalue)
-    {
-        self.pos1 = '-16 -16 0';
-        self.pos2 = '16 16 48';
-    }
+       {
+               self.pos1 = '-16 -16 0';
+               self.pos2 = '16 16 48';
+       }
        else
-    {
-        self.pos1 = '-16 -16 0';
-        self.pos2 = '16 16 32';
-    }
-    setsize (self, self.pos1, self.pos2);
+       {
+               self.pos1 = '-16 -16 0';
+               self.pos2 = '16 16 32';
+       }
+       setsize (self, self.pos1, self.pos2);
 
-    if(itemflags & FL_POWERUP)
-        self.ItemStatus |= ITS_ANIMATE1;
+       self.SendFlags |= ISF_SIZE;
+
+       if(itemflags & FL_POWERUP)
+               self.ItemStatus |= ITS_ANIMATE1;
 
        if(self.armorvalue || self.health)
-        self.ItemStatus |= ITS_ANIMATE2;
+               self.ItemStatus |= ITS_ANIMATE2;
 
        if(itemflags & FL_WEAPON)
        {
                if (self.classname != "droppedweapon") // if dropped, colormap is already set up nicely
-            self.colormap = 1024; // color shirt=0 pants=0 grey
-        else
-            self.gravity = 1;
+                       self.colormap = 1024; // color shirt=0 pants=0 grey
+               else
+                       self.gravity = 1;
 
                self.ItemStatus |= ITS_ANIMATE1;
                self.ItemStatus |= ISF_COLORMAP;
@@ -1108,37 +1186,46 @@ void StartItem (string itemmodel, string pickupsound, float defaultrespawntime,
        else
                Item_Reset();
 
-    Net_LinkEntity(self, FALSE, 0, ItemSend);
-       
-       self.SendFlags |= ISF_SIZE;
-       if(self.angles)
-               self.SendFlags |= ISF_ANGLES;
+       Net_LinkEntity(self, !((itemflags & FL_POWERUP) || self.health || self.armorvalue), 0, ItemSend);
 
        // call this hook after everything else has been done
-       if(MUTATOR_CALLHOOK(Item_Spawn))
+       if(MUTATOR_CALLHOOK(Item_Spawn, self))
        {
-               startitem_failed = TRUE;
+               startitem_failed = true;
                remove(self);
                return;
        }
 }
+
+string Item_Model(string item_mdl)
+{
+       string output = strcat("models/items/", item_mdl);
+       MUTATOR_CALLHOOK(ItemModel, item_mdl, output);
+       return strzone(item_model_output);
+}
+
+void StartItemA (entity a)
+{
+    self.itemdef = a;
+    StartItem(Item_Model(a.m_model), a.m_sound, a.m_respawntime(), a.m_respawntimejitter(), a.m_name, a.m_itemid, 0, a.m_itemflags, a.m_pickupevalfunc, a.m_botvalue);
+}
+
 void spawnfunc_item_rockets (void) {
        if(!self.ammo_rockets)
                self.ammo_rockets = g_pickup_rockets;
        if(!self.pickup_anyway)
                self.pickup_anyway = g_pickup_ammo_anyway;
-       StartItem ("models/items/a_rockets.md3", "misc/itempickup.wav", g_pickup_respawntime_ammo, g_pickup_respawntimejitter_ammo, "rockets", IT_ROCKETS, 0, 0, commodity_pickupevalfunc, 3000);
+    StartItemA (ITEM_Rockets);
 }
 
-void spawnfunc_item_shells (void);
 void spawnfunc_item_bullets (void) {
        if(!weaponswapping)
        if(autocvar_sv_q3acompat_machineshotgunswap)
        if(self.classname != "droppedweapon")
        {
-               weaponswapping = TRUE;
+               weaponswapping = true;
                spawnfunc_item_shells();
-               weaponswapping = FALSE;
+               weaponswapping = false;
                return;
        }
 
@@ -1146,7 +1233,7 @@ void spawnfunc_item_bullets (void) {
                self.ammo_nails = g_pickup_nails;
        if(!self.pickup_anyway)
                self.pickup_anyway = g_pickup_ammo_anyway;
-       StartItem ("models/items/a_bullets.mdl", "misc/itempickup.wav", g_pickup_respawntime_ammo, g_pickup_respawntimejitter_ammo, "bullets", IT_NAILS, 0, 0, commodity_pickupevalfunc, 2000);
+    StartItemA (ITEM_Bullets);
 }
 
 void spawnfunc_item_cells (void) {
@@ -1154,7 +1241,7 @@ void spawnfunc_item_cells (void) {
                self.ammo_cells = g_pickup_cells;
        if(!self.pickup_anyway)
                self.pickup_anyway = g_pickup_ammo_anyway;
-       StartItem ("models/items/a_cells.md3", "misc/itempickup.wav", g_pickup_respawntime_ammo, g_pickup_respawntimejitter_ammo, "cells", IT_CELLS, 0, 0, commodity_pickupevalfunc, 2000);
+       StartItemA (ITEM_Cells);
 }
 
 void spawnfunc_item_plasma()
@@ -1163,7 +1250,7 @@ void spawnfunc_item_plasma()
                self.ammo_plasma = g_pickup_plasma;
        if(!self.pickup_anyway)
                self.pickup_anyway = g_pickup_ammo_anyway;
-       StartItem ("models/items/a_cells.md3", "misc/itempickup.wav", g_pickup_respawntime_ammo, g_pickup_respawntimejitter_ammo, "plasma", IT_PLASMA, 0, 0, commodity_pickupevalfunc, 2000);
+       StartItemA (ITEM_Plasma);
 }
 
 void spawnfunc_item_shells (void) {
@@ -1171,9 +1258,9 @@ void spawnfunc_item_shells (void) {
        if(autocvar_sv_q3acompat_machineshotgunswap)
        if(self.classname != "droppedweapon")
        {
-               weaponswapping = TRUE;
+               weaponswapping = true;
                spawnfunc_item_bullets();
-               weaponswapping = FALSE;
+               weaponswapping = false;
                return;
        }
 
@@ -1181,7 +1268,7 @@ void spawnfunc_item_shells (void) {
                self.ammo_shells = g_pickup_shells;
        if(!self.pickup_anyway)
                self.pickup_anyway = g_pickup_ammo_anyway;
-       StartItem ("models/items/a_shells.md3", "misc/itempickup.wav", g_pickup_respawntime_ammo, g_pickup_respawntimejitter_ammo, "shells", IT_SHELLS, 0, 0, commodity_pickupevalfunc, 500);
+       StartItemA (ITEM_Shells);
 }
 
 void spawnfunc_item_armor_small (void) {
@@ -1191,7 +1278,7 @@ void spawnfunc_item_armor_small (void) {
                self.max_armorvalue = g_pickup_armorsmall_max;
        if(!self.pickup_anyway)
                self.pickup_anyway = g_pickup_armorsmall_anyway;
-       StartItem ("models/items/item_armor_small.md3", "misc/armor1.wav", g_pickup_respawntime_short, g_pickup_respawntimejitter_short, "5 Armor", IT_ARMOR_SHARD, 0, 0, commodity_pickupevalfunc, BOT_PICKUP_RATING_LOW);
+       StartItemA (ITEM_ArmorSmall);
 }
 
 void spawnfunc_item_armor_medium (void) {
@@ -1201,7 +1288,7 @@ void spawnfunc_item_armor_medium (void) {
                self.max_armorvalue = g_pickup_armormedium_max;
        if(!self.pickup_anyway)
                self.pickup_anyway = g_pickup_armormedium_anyway;
-       StartItem ("models/items/item_armor_medium.md3", "misc/armor10.wav", g_pickup_respawntime_medium, g_pickup_respawntimejitter_medium, "25 Armor", IT_ARMOR, 0, 0, commodity_pickupevalfunc, BOT_PICKUP_RATING_MID);
+       StartItemA (ITEM_ArmorMedium);
 }
 
 void spawnfunc_item_armor_big (void) {
@@ -1211,7 +1298,7 @@ void spawnfunc_item_armor_big (void) {
                self.max_armorvalue = g_pickup_armorbig_max;
        if(!self.pickup_anyway)
                self.pickup_anyway = g_pickup_armorbig_anyway;
-       StartItem ("models/items/item_armor_big.md3", "misc/armor17_5.wav", g_pickup_respawntime_long, g_pickup_respawntimejitter_long, "50 Armor", IT_ARMOR, 0, 0, commodity_pickupevalfunc, 20000);
+       StartItemA (ITEM_ArmorLarge);
 }
 
 void spawnfunc_item_armor_large (void) {
@@ -1221,7 +1308,7 @@ void spawnfunc_item_armor_large (void) {
                self.max_armorvalue = g_pickup_armorlarge_max;
        if(!self.pickup_anyway)
                self.pickup_anyway = g_pickup_armorlarge_anyway;
-       StartItem ("models/items/item_armor_large.md3", "misc/armor25.wav", g_pickup_respawntime_long, g_pickup_respawntimejitter_long, "100 Armor", IT_ARMOR, 0, 0, commodity_pickupevalfunc, BOT_PICKUP_RATING_HIGH);
+       StartItemA (ITEM_ArmorMega);
 }
 
 void spawnfunc_item_health_small (void) {
@@ -1231,7 +1318,7 @@ void spawnfunc_item_health_small (void) {
                self.health = g_pickup_healthsmall;
        if(!self.pickup_anyway)
                self.pickup_anyway = g_pickup_healthsmall_anyway;
-       StartItem ("models/items/g_h1.md3", "misc/minihealth.wav", g_pickup_respawntime_short, g_pickup_respawntimejitter_short, "5 Health", IT_5HP, 0, 0, commodity_pickupevalfunc, BOT_PICKUP_RATING_LOW);
+       StartItemA (ITEM_HealthSmall);
 }
 
 void spawnfunc_item_health_medium (void) {
@@ -1241,7 +1328,7 @@ void spawnfunc_item_health_medium (void) {
                self.health = g_pickup_healthmedium;
        if(!self.pickup_anyway)
                self.pickup_anyway = g_pickup_healthmedium_anyway;
-       StartItem ("models/items/g_h25.md3", "misc/mediumhealth.wav", g_pickup_respawntime_short, g_pickup_respawntimejitter_short, "25 Health", IT_25HP, 0, 0, commodity_pickupevalfunc, BOT_PICKUP_RATING_MID);
+    StartItemA (ITEM_HealthMedium);
 }
 
 void spawnfunc_item_health_large (void) {
@@ -1251,17 +1338,17 @@ void spawnfunc_item_health_large (void) {
                self.health = g_pickup_healthlarge;
        if(!self.pickup_anyway)
                self.pickup_anyway = g_pickup_healthlarge_anyway;
-       StartItem ("models/items/g_h50.md3", "misc/mediumhealth.wav", g_pickup_respawntime_medium, g_pickup_respawntimejitter_medium, "50 Health", IT_25HP, 0, 0, commodity_pickupevalfunc, BOT_PICKUP_RATING_MID);
+       StartItemA (ITEM_HealthLarge);
 }
 
 void spawnfunc_item_health_mega (void) {
-               if(!self.max_health)
-                       self.max_health = g_pickup_healthmega_max;
-               if(!self.health)
-                       self.health = g_pickup_healthmega;
-               if(!self.pickup_anyway)
-                       self.pickup_anyway = g_pickup_healthmega_anyway;
-               StartItem ("models/items/g_h100.md3", "misc/megahealth.wav", g_pickup_respawntime_long, g_pickup_respawntimejitter_long, "100 Health", IT_HEALTH, 0, 0, commodity_pickupevalfunc, BOT_PICKUP_RATING_HIGH);
+    if(!self.max_health)
+        self.max_health = g_pickup_healthmega_max;
+    if(!self.health)
+        self.health = g_pickup_healthmega;
+    if(!self.pickup_anyway)
+        self.pickup_anyway = g_pickup_healthmega_anyway;
+    StartItemA (ITEM_HealthMega);
 }
 
 // support old misnamed entities
@@ -1275,13 +1362,13 @@ void spawnfunc_item_strength (void) {
                precache_sound("weapons/strength_fire.wav");
                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);
+               StartItemA (ITEM_Strength);
 }
 
 void spawnfunc_item_invincible (void) {
                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);
+               StartItemA (ITEM_Shield);
 }
 
 // compatibility:
@@ -1315,6 +1402,7 @@ void spawnfunc_target_items (void)
 {
        float n, i, j;
        entity e;
+       string s;
 
        self.use = target_items_use;
        if(!self.strength_finished)
@@ -1329,7 +1417,7 @@ void spawnfunc_target_items (void)
        precache_sound("misc/armor25.wav");
        precache_sound("misc/powerup.wav");
        precache_sound("misc/poweroff.wav");
-       precache_sound("weapons/weaponpickup.wav");
+       precache_sound(W_Sound("weaponpickup"));
 
        n = tokenize_console(self.netname);
        if(argv(0) == "give")
@@ -1343,17 +1431,18 @@ void spawnfunc_target_items (void)
                        if     (argv(i) == "unlimited_ammo")         self.items |= IT_UNLIMITED_AMMO;
                        else if(argv(i) == "unlimited_weapon_ammo")  self.items |= IT_UNLIMITED_WEAPON_AMMO;
                        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) == "strength")               self.items |= ITEM_Strength.m_itemid;
+                       else if(argv(i) == "invincible")             self.items |= ITEM_Shield.m_itemid;
                        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 if(argv(i) == "jetpack")                self.items |= ITEM_Jetpack.m_itemid;
+                       else if(argv(i) == "fuel_regen")             self.items |= ITEM_JetpackRegen.m_itemid;
                        else
                        {
                                for(j = WEP_FIRST; j <= WEP_LAST; ++j)
                                {
                                        e = get_weaponinfo(j);
-                                       if(argv(i) == e.netname)
+                                       s = W_UndeprecateName(argv(i));
+                                       if(s == e.netname)
                                        {
                                                self.weapons |= WepSet_FromWeapon(j);
                                                if(self.spawnflags == 0 || self.spawnflags == 2)
@@ -1362,7 +1451,7 @@ void spawnfunc_target_items (void)
                                        }
                                }
                                if(j > WEP_LAST)
-                                       print("target_items: invalid item ", argv(i), "\n");
+                                       LOG_INFO("target_items: invalid item ", argv(i), "\n");
                        }
                }
 
@@ -1390,20 +1479,17 @@ void spawnfunc_target_items (void)
                else
                {
                        error("invalid spawnflags");
-#ifdef GMQCC
-                       itemprefix = string_null;
-                       valueprefix = string_null;
-#endif
+                       itemprefix = valueprefix = string_null;
                }
 
                self.netname = "";
                self.netname = sprintf("%s %s%d %s", self.netname, itemprefix, !!(self.items & IT_UNLIMITED_WEAPON_AMMO), "unlimited_weapon_ammo");
                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.strength_finished * !!(self.items & ITEM_Strength.m_itemid), "strength");
+               self.netname = sprintf("%s %s%d %s", self.netname, valueprefix, self.invincible_finished * !!(self.items & ITEM_Shield.m_itemid), "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");
+               self.netname = sprintf("%s %s%d %s", self.netname, itemprefix, !!(self.items & ITEM_Jetpack.m_itemid), "jetpack");
+               self.netname = sprintf("%s %s%d %s", self.netname, itemprefix, !!(self.items & ITEM_JetpackRegen.m_itemid), "fuel_regen");
                if(self.ammo_shells != 0) self.netname = sprintf("%s %s%d %s", self.netname, valueprefix, max(0, self.ammo_shells), "shells");
                if(self.ammo_nails != 0) self.netname = sprintf("%s %s%d %s", self.netname, valueprefix, max(0, self.ammo_nails), "nails");
                if(self.ammo_rockets != 0) self.netname = sprintf("%s %s%d %s", self.netname, valueprefix, max(0, self.ammo_rockets), "rockets");
@@ -1443,29 +1529,29 @@ void spawnfunc_item_fuel(void)
                self.ammo_fuel = g_pickup_fuel;
        if(!self.pickup_anyway)
                self.pickup_anyway = g_pickup_ammo_anyway;
-       StartItem ("models/items/g_fuel.md3", "misc/itempickup.wav", g_pickup_respawntime_ammo, g_pickup_respawntimejitter_ammo, "Fuel", IT_FUEL, 0, 0, commodity_pickupevalfunc, BOT_PICKUP_RATING_LOW);
+       StartItemA (ITEM_JetpackFuel);
 }
 
 void spawnfunc_item_fuel_regen(void)
 {
-       if(start_items & IT_FUEL_REGEN)
+       if(start_items & ITEM_JetpackRegen.m_itemid)
        {
                spawnfunc_item_fuel();
                return;
        }
-       StartItem ("models/items/g_fuelregen.md3", "misc/itempickup.wav", g_pickup_respawntime_powerup, g_pickup_respawntimejitter_powerup, "Fuel regenerator", IT_FUEL_REGEN, 0, FL_POWERUP, commodity_pickupevalfunc, BOT_PICKUP_RATING_LOW);
+       StartItemA (ITEM_JetpackRegen);
 }
 
 void spawnfunc_item_jetpack(void)
 {
        if(!self.ammo_fuel)
                self.ammo_fuel = g_pickup_fuel_jetpack;
-       if(start_items & IT_JETPACK)
+       if(start_items & ITEM_Jetpack.m_itemid)
        {
                spawnfunc_item_fuel();
                return;
        }
-       StartItem ("models/items/g_jetpack.md3", "misc/itempickup.wav", g_pickup_respawntime_powerup, g_pickup_respawntimejitter_powerup, "Jet pack", IT_JETPACK, 0, FL_POWERUP, commodity_pickupevalfunc, BOT_PICKUP_RATING_LOW);
+       StartItemA (ITEM_Jetpack);
 }
 
 float GiveWeapon(entity e, float wpn, float op, float val)
@@ -1501,56 +1587,56 @@ float GiveWeapon(entity e, float wpn, float op, float val)
 float GiveBit(entity e, .float fld, float bit, float op, float val)
 {
        float v0, v1;
-       v0 = (e.fld & bit);
+       v0 = (e.(fld) & bit);
        switch(op)
        {
                case OP_SET:
                        if(val > 0)
-                               e.fld |= bit;
+                               e.(fld) |= bit;
                        else
-                               e.fld &= ~bit;
+                               e.(fld) &= ~bit;
                        break;
                case OP_MIN:
                case OP_PLUS:
                        if(val > 0)
-                               e.fld |= bit;
+                               e.(fld) |= bit;
                        break;
                case OP_MAX:
                        if(val <= 0)
-                               e.fld &= ~bit;
+                               e.(fld) &= ~bit;
                        break;
                case OP_MINUS:
                        if(val > 0)
-                               e.fld &= ~bit;
+                               e.(fld) &= ~bit;
                        break;
        }
-       v1 = (e.fld & bit);
+       v1 = (e.(fld) & bit);
        return (v0 != v1);
 }
 
 float GiveValue(entity e, .float fld, float op, float val)
 {
        float v0, v1;
-       v0 = e.fld;
+       v0 = e.(fld);
        switch(op)
        {
                case OP_SET:
-                       e.fld = val;
+                       e.(fld) = val;
                        break;
                case OP_MIN:
-                       e.fld = max(e.fld, val); // min 100 cells = at least 100 cells
+                       e.(fld) = max(e.(fld), val); // min 100 cells = at least 100 cells
                        break;
                case OP_MAX:
-                       e.fld = min(e.fld, val);
+                       e.(fld) = min(e.(fld), val);
                        break;
                case OP_PLUS:
-                       e.fld += val;
+                       e.(fld) += val;
                        break;
                case OP_MINUS:
-                       e.fld -= val;
+                       e.(fld) -= val;
                        break;
        }
-       v1 = e.fld;
+       v1 = e.(fld);
        return (v0 != v1);
 }
 
@@ -1573,9 +1659,9 @@ void GiveSound(entity e, float v0, float v1, float t, string snd_incr, string sn
 void GiveRot(entity e, float v0, float v1, .float rotfield, float rottime, .float regenfield, float regentime)
 {
        if(v0 < v1)
-               e.rotfield = max(e.rotfield, time + rottime);
+               e.(rotfield) = max(e.(rotfield), time + rottime);
        else if(v0 > v1)
-               e.regenfield = max(e.regenfield, time + regentime);
+               e.(regenfield) = max(e.(regenfield), time + regentime);
 }
 float GiveItems(entity e, float beginarg, float endarg)
 {
@@ -1589,10 +1675,10 @@ float GiveItems(entity e, float beginarg, float endarg)
 
        got = 0;
 
-       _switchweapon = FALSE;
+       _switchweapon = false;
        if (e.autoswitch)
                if (e.switchweapon == w_getbestweapon(e))
-                       _switchweapon = TRUE;
+                       _switchweapon = true;
 
        e.strength_finished = max(0, e.strength_finished - time);
        e.invincible_finished = max(0, e.invincible_finished - time);
@@ -1640,13 +1726,13 @@ float GiveItems(entity e, float beginarg, float endarg)
                                op = OP_MINUS;
                                continue;
                        case "ALL":
-                               got += GiveBit(e, items, IT_FUEL_REGEN, op, val);
+                               got += GiveBit(e, items, ITEM_JetpackRegen.m_itemid, op, val);
                                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);
+                               got += GiveBit(e, items, ITEM_Jetpack.m_itemid, op, val);
                                got += GiveValue(e, health, op, val);
                                got += GiveValue(e, armorvalue, op, val);
                        case "allweapons":
@@ -1675,10 +1761,10 @@ float GiveItems(entity e, float beginarg, float endarg)
                                got += GiveBit(e, items, IT_UNLIMITED_SUPERWEAPONS, op, val);
                                break;
                        case "jetpack":
-                               got += GiveBit(e, items, IT_JETPACK, op, val);
+                               got += GiveBit(e, items, ITEM_Jetpack.m_itemid, op, val);
                                break;
                        case "fuel_regen":
-                               got += GiveBit(e, items, IT_FUEL_REGEN, op, val);
+                               got += GiveBit(e, items, ITEM_JetpackRegen.m_itemid, op, val);
                                break;
                        case "strength":
                                got += GiveValue(e, strength_finished, op, val);
@@ -1725,23 +1811,23 @@ float GiveItems(entity e, float beginarg, float endarg)
                                        }
                                }
                                if(j > WEP_LAST)
-                                       print("give: invalid item ", cmd, "\n");
+                                       LOG_INFO("give: invalid item ", cmd, "\n");
                                break;
                }
                val = 999;
                op = OP_SET;
        }
 
-       POSTGIVE_BIT(e, items, IT_FUEL_REGEN, "misc/itempickup.wav", string_null);
+       POSTGIVE_BIT(e, items, ITEM_JetpackRegen.m_itemid, "misc/itempickup.wav", string_null);
        POSTGIVE_BIT(e, items, IT_UNLIMITED_SUPERWEAPONS, "misc/powerup.wav", "misc/poweroff.wav");
        POSTGIVE_BIT(e, items, IT_UNLIMITED_WEAPON_AMMO, "misc/powerup.wav", "misc/poweroff.wav");
-       POSTGIVE_BIT(e, items, IT_JETPACK, "misc/itempickup.wav", string_null);
+       POSTGIVE_BIT(e, items, ITEM_Jetpack.m_itemid, "misc/itempickup.wav", string_null);
        for(j = WEP_FIRST; j <= WEP_LAST; ++j)
        {
                wi = get_weaponinfo(j);
                if(wi.weapon)
                {
-                       POSTGIVE_WEAPON(e, j, "weapons/weaponpickup.wav", string_null);
+                       POSTGIVE_WEAPON(e, j, W_Sound("weaponpickup"), string_null);
                        if (!(save_weapons & WepSet_FromWeapon(j)))
                                if(e.weapons & WepSet_FromWeapon(j))
                                        WEP_ACTION(wi.weapon, WR_INIT);
@@ -1776,7 +1862,7 @@ float GiveItems(entity e, float beginarg, float endarg)
                e.superweapons_finished += time;
 
        if (!(e.weapons & WepSet_FromWeapon(e.switchweapon)))
-               _switchweapon = TRUE;
+               _switchweapon = true;
        if(_switchweapon)
                W_SwitchWeapon_Force(e, w_getbestweapon(e));