]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/common/t_items.qc
Proper handling of expiring items.
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / t_items.qc
index a1b0ced6966e57600a16366048376d4b7e873ba5..da491b71871eb86ead9b45a522938d93191461fe 100644 (file)
@@ -682,6 +682,51 @@ void Item_ScheduleInitialRespawn(entity e)
        Item_ScheduleRespawnIn(e, max(0, game_starttime - time) + ((e.respawntimestart) ? e.respawntimestart : ITEM_RESPAWNTIME_INITIAL(e)));
 }
 
+void GiveRandomWeapons(entity receiver, int num_weapons, string weapon_names,
+       entity ammo_entity)
+{
+       if (num_weapons == 0)
+       {
+               return;
+       }
+       int num_potential_weapons = tokenize_console(weapon_names);
+       for (int give_attempt = 0; give_attempt < num_weapons; ++give_attempt)
+       {
+               RandomSelection_Init();
+               for (int weapon_index = 0; weapon_index < num_potential_weapons;
+                       ++weapon_index)
+               {
+                       string weapon = argv(weapon_index);
+                       FOREACH(Weapons, it != WEP_Null,
+                       {
+                               // Finding a weapon which player doesn't have.
+                               if (!(receiver.weapons & it.m_wepset) && (it.netname == weapon))
+                               {
+                                       RandomSelection_AddEnt(it, 1, 1);
+                                       break;
+                               }
+                       });
+               }
+               if (RandomSelection_chosen_ent == NULL)
+               {
+                       return;
+               }
+               receiver.weapons |= RandomSelection_chosen_ent.m_wepset;
+               if (RandomSelection_chosen_ent.ammo_type == RESOURCE_NONE)
+               {
+                       continue;
+               }
+               if (GetResourceAmount(receiver,
+                       RandomSelection_chosen_ent.ammo_type) != 0)
+               {
+                       continue;
+               }
+               GiveResource(receiver, RandomSelection_chosen_ent.ammo_type,
+                       GetResourceAmount(ammo_entity,
+                       RandomSelection_chosen_ent.ammo_type));
+       }
+}
+
 float Item_GiveAmmoTo(entity item, entity player, int resource_type, float ammomax)
 {
        float amount = GetResourceAmount(item, resource_type);
@@ -834,9 +879,8 @@ LABEL(skip)
 
 void Item_Touch(entity this, entity toucher)
 {
-
        // remove the item if it's currnetly in a NODROP brush or hits a NOIMPACT surface (such as sky)
-       if (this.classname == "droppedweapon")
+       if (Item_IsLoot(this))
        {
                if (ITEM_TOUCH_NEEDKILL())
                {
@@ -861,17 +905,16 @@ void Item_Touch(entity this, entity toucher)
 
        toucher = M_ARGV(1, entity);
 
-       if (this.classname == "droppedweapon")
+       if (Item_IsExpiring(this))
        {
                this.strength_finished = max(0, this.strength_finished - time);
                this.invincible_finished = max(0, this.invincible_finished - time);
                this.superweapons_finished = max(0, this.superweapons_finished - time);
        }
-       entity it = this.itemdef;
-       bool gave = ITEM_HANDLE(Pickup, it, this, toucher);
+       bool gave = ITEM_HANDLE(Pickup, this.itemdef, this, toucher);
        if (!gave)
        {
-               if (this.classname == "droppedweapon")
+               if (Item_IsExpiring(this))
                {
                        // undo what we did above
                        this.strength_finished += time;
@@ -888,29 +931,40 @@ LABEL(pickup)
        Send_Effect(EFFECT_ITEM_PICKUP, CENTER_OR_VIEWOFS(this), '0 0 0', 1);
        _sound (toucher, (this.itemdef.instanceOfPowerup ? CH_TRIGGER_SINGLE : CH_TRIGGER), (this.item_pickupsound ? this.item_pickupsound : Sound_fixpath(this.item_pickupsound_ent)), VOL_BASE, ATTEN_NORM);
 
-       if (this.classname == "droppedweapon")
+       MUTATOR_CALLHOOK(ItemTouched, this, toucher);
+       if (wasfreed(this))
+       {
+               return;
+       }
+
+       if (Item_IsLoot(this))
+       {
                delete(this);
-       else if (this.spawnshieldtime)
+               return;
+       }
+       if (!this.spawnshieldtime)
        {
-               entity e;
-               if(this.team)
+               return;
+       }
+       entity e;
+       if (this.team)
+       {
+               RandomSelection_Init();
+               IL_EACH(g_items, it.team == this.team,
                {
-                       RandomSelection_Init();
-                       IL_EACH(g_items, it.team == this.team,
+                       if (it.itemdef) // is a registered item
                        {
-                               if(it.itemdef) // is a registered item
-                               {
-                                       Item_Show(it, -1);
-                                       RandomSelection_AddEnt(it, it.cnt, 0);
-                               }
-                       });
-                       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;
-               Item_ScheduleRespawn(e);
+                               Item_Show(it, -1);
+                               it.scheduledrespawntime = 0;
+                               RandomSelection_AddEnt(it, it.cnt, 0);
+                       }
+               });
+               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;
+       Item_ScheduleRespawn(e);
 }
 
 void Item_Reset(entity this)
@@ -918,16 +972,19 @@ void Item_Reset(entity this)
        Item_Show(this, !this.state);
        setorigin(this, this.origin);
 
-       if (this.classname != "droppedweapon")
+       if (Item_IsLoot(this))
        {
-               setthink(this, Item_Think);
-               this.nextthink = time;
-
-               if (this.waypointsprite_attached)
-                       WaypointSprite_Kill(this.waypointsprite_attached);
-
-               if (this.itemdef.instanceOfPowerup || (this.weapons & WEPSET_SUPERWEAPONS)) // do not spawn powerups initially!
-                       Item_ScheduleInitialRespawn(this);
+               return;
+       }
+       setthink(this, Item_Think);
+       this.nextthink = time;
+       if (this.waypointsprite_attached)
+       {
+               WaypointSprite_Kill(this.waypointsprite_attached);
+       }
+       if (this.itemdef.instanceOfPowerup || (this.weapons & WEPSET_SUPERWEAPONS)) // do not spawn powerups initially!
+       {
+               Item_ScheduleInitialRespawn(this);
        }
 }
 
@@ -1159,11 +1216,9 @@ void _StartItem(entity this, entity def, float defaultrespawntime, float default
                return;
        }
 
-       // is it a dropped weapon?
-       if (this.classname == "droppedweapon")
+       if (Item_IsLoot(this))
        {
                this.reset = SUB_Remove;
-               // it's a dropped weapon
                set_movetype(this, MOVETYPE_TOSS);
 
                // Savage: remove thrown items after a certain period of time ("garbage collection")
@@ -1173,7 +1228,7 @@ void _StartItem(entity this, entity def, float defaultrespawntime, float default
                this.takedamage = DAMAGE_YES;
                this.event_damage = Item_Damage;
 
-               if(this.strength_finished || this.invincible_finished || this.superweapons_finished)
+               if (Item_IsExpiring(this))
                {
                        // if item is worthless after a timer, have it expire then
                        this.nextthink = max(this.strength_finished, this.invincible_finished, this.superweapons_finished);
@@ -1324,6 +1379,13 @@ void _StartItem(entity this, entity def, float defaultrespawntime, float default
 
 void StartItem(entity this, GameItem def)
 {
+    def = def.m_spawnfunc_hookreplace(def, this);
+    if (def.spawnflags & ITEM_FLAG_MUTATORBLOCKED)
+    {
+        delete(this);
+        return;
+    }
+    this.classname = def.m_canonical_spawnfunc;
     _StartItem(
        this,
        this.itemdef = def,
@@ -1380,111 +1442,6 @@ void setItemGroupCount()
        }
 }
 
-spawnfunc(item_rockets)
-{
-    StartItem(this, ITEM_Rockets);
-}
-
-spawnfunc(item_bullets)
-{
-       if(!weaponswapping && autocvar_sv_q3acompat_machineshotgunswap &&
-          (this.classname != "droppedweapon"))
-       {
-               weaponswapping = true;
-               spawnfunc_item_shells(this);
-               weaponswapping = false;
-               return;
-       }
-
-    StartItem(this, ITEM_Bullets);
-}
-
-spawnfunc(item_cells)
-{
-       StartItem(this, ITEM_Cells);
-}
-
-spawnfunc(item_plasma)
-{
-       StartItem(this, ITEM_Plasma);
-}
-
-spawnfunc(item_shells)
-{
-       if(!weaponswapping && autocvar_sv_q3acompat_machineshotgunswap &&
-          (this.classname != "droppedweapon"))
-       {
-               weaponswapping = true;
-               spawnfunc_item_bullets(this);
-               weaponswapping = false;
-               return;
-       }
-
-       StartItem(this, ITEM_Shells);
-}
-
-spawnfunc(item_armor_small)
-{
-       StartItem(this, ITEM_ArmorSmall);
-}
-
-spawnfunc(item_armor_medium)
-{
-       StartItem(this, ITEM_ArmorMedium);
-}
-
-spawnfunc(item_armor_big)
-{
-       StartItem(this, ITEM_ArmorBig);
-}
-
-spawnfunc(item_armor_mega)
-{
-       StartItem(this, ITEM_ArmorMega);
-}
-
-spawnfunc(item_health_small)
-{
-       StartItem(this, ITEM_HealthSmall);
-}
-
-spawnfunc(item_health_medium)
-{
-    StartItem(this, ITEM_HealthMedium);
-}
-
-spawnfunc(item_health_big)
-{
-       StartItem(this, ITEM_HealthBig);
-}
-
-spawnfunc(item_health_mega)
-{
-    StartItem(this, ITEM_HealthMega);
-}
-
-// support old misnamed entities
-spawnfunc(item_armor1) { spawnfunc_item_armor_small(this); }  // FIXME: in Quake this is green armor, in Xonotic maps it is an armor shard
-spawnfunc(item_armor25) { spawnfunc_item_armor_mega(this); }
-spawnfunc(item_armor_large) { spawnfunc_item_armor_mega(this); }
-spawnfunc(item_health1) { spawnfunc_item_health_small(this); }
-spawnfunc(item_health25) { spawnfunc_item_health_medium(this); }
-spawnfunc(item_health_large) { spawnfunc_item_health_big(this); }
-spawnfunc(item_health100) { spawnfunc_item_health_mega(this); }
-
-spawnfunc(item_strength)
-{
-       StartItem(this, ITEM_Strength);
-}
-
-spawnfunc(item_invincible)
-{
-       StartItem(this, ITEM_Shield);
-}
-
-// compatibility:
-spawnfunc(item_quad) { this.classname = "item_strength";spawnfunc_item_strength(this);}
-
 void target_items_use(entity this, entity actor, entity trigger)
 {
        if(actor.classname == "droppedweapon")
@@ -1624,31 +1581,6 @@ spawnfunc(target_items)
        }
 }
 
-spawnfunc(item_fuel)
-{
-       StartItem(this, ITEM_JetpackFuel);
-}
-
-spawnfunc(item_fuel_regen)
-{
-       if(start_items & ITEM_JetpackRegen.m_itemid)
-       {
-               spawnfunc_item_fuel(this);
-               return;
-       }
-       StartItem(this, ITEM_JetpackRegen);
-}
-
-spawnfunc(item_jetpack)
-{
-       if(start_items & ITEM_Jetpack.m_itemid)
-       {
-               spawnfunc_item_fuel(this);
-               return;
-       }
-       StartItem(this, ITEM_Jetpack);
-}
-
 float GiveWeapon(entity e, float wpn, float op, float val)
 {
        WepSet v0, v1;