]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/common/t_items.qc
Properly support team field on trigger_multiple
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / t_items.qc
index f794d77a974d7b128df130ceeb306d79087e754d..fa6d0f6f313510dd1bc6a8e1a6e921a425d7e1b0 100644 (file)
@@ -533,7 +533,7 @@ void Item_Respawn (entity this)
 
 void Item_RespawnCountdown (entity this)
 {
-       if(this.count >= ITEM_RESPAWN_TICKS)
+       if(this.item_respawncounter >= ITEM_RESPAWN_TICKS)
        {
                if(this.waypointsprite_attached)
                        WaypointSprite_Kill(this.waypointsprite_attached);
@@ -542,8 +542,8 @@ void Item_RespawnCountdown (entity this)
        else
        {
                this.nextthink = time + 1;
-               this.count += 1;
-               if(this.count == 1)
+               this.item_respawncounter += 1;
+               if(this.item_respawncounter == 1)
                {
                        do {
                                {
@@ -584,7 +584,7 @@ void Item_RespawnCountdown (entity this)
                        });
 
                        WaypointSprite_Ping(this.waypointsprite_attached);
-                       //WaypointSprite_UpdateHealth(this.waypointsprite_attached, this.count);
+                       //WaypointSprite_UpdateHealth(this.waypointsprite_attached, this.item_respawncounter);
                }
        }
 }
@@ -607,7 +607,7 @@ void Item_ScheduleRespawnIn(entity e, float t)
                setthink(e, Item_RespawnCountdown);
                e.nextthink = time + max(0, t - ITEM_RESPAWN_TICKS);
                e.scheduledrespawntime = e.nextthink + ITEM_RESPAWN_TICKS;
-               e.count = 0;
+               e.item_respawncounter = 0;
                if(Item_ItemsTime_Allow(e.itemdef) || (e.weapons & WEPSET_SUPERWEAPONS))
                {
                        t = Item_ItemsTime_UpdateTime(e, e.scheduledrespawntime);
@@ -682,191 +682,74 @@ void Item_ScheduleInitialRespawn(entity e)
        Item_ScheduleRespawnIn(e, max(0, game_starttime - time) + ((e.respawntimestart) ? e.respawntimestart : ITEM_RESPAWNTIME_INITIAL(e)));
 }
 
-int GetResourceType(.float resource_property)
+void GiveRandomWeapons(entity receiver, int num_weapons, string weapon_names,
+       entity ammo_entity)
 {
-       switch (resource_property)
-       {
-               case health: { return RESOURCE_HEALTH; }
-               case armorvalue: { return RESOURCE_ARMOR; }
-               case ammo_shells: { return RESOURCE_SHELLS; }
-               case ammo_nails: { return RESOURCE_BULLETS; }
-               case ammo_rockets: { return RESOURCE_ROCKETS; }
-               case ammo_cells: { return RESOURCE_CELLS; }
-               case ammo_plasma: { return RESOURCE_PLASMA; }
-               case ammo_fuel: { return RESOURCE_FUEL; }
-       }
-       error("GetResourceType: Invalid property.");
-       return 0;
-}
-
-.float GetResourceProperty(int resource_type)
-{
-       switch (resource_type)
-       {
-               case RESOURCE_HEALTH: { return health; }
-               case RESOURCE_ARMOR: { return armorvalue; }
-               case RESOURCE_SHELLS: { return ammo_shells; }
-               case RESOURCE_BULLETS: { return ammo_nails; }
-               case RESOURCE_ROCKETS: { return ammo_rockets; }
-               case RESOURCE_CELLS: { return ammo_cells; }
-               case RESOURCE_PLASMA: { return ammo_plasma; }
-               case RESOURCE_FUEL: { return ammo_fuel; }
-       }
-       error("GetResourceProperty: Invalid resource type.");
-       return health;
-}
-
-float GetResourceLimit(int resource_type)
-{
-       float limit;
-       switch (resource_type)
-       {
-               case RESOURCE_HEALTH:
-               {
-                       limit = autocvar_g_balance_health_limit;
-                       break;
-               }
-               case RESOURCE_ARMOR:
-               {
-                       limit = autocvar_g_balance_armor_limit;
-                       break;
-               }
-               case RESOURCE_SHELLS:
-               {
-                       limit = g_pickup_shells_max;
-                       break;
-               }
-               case RESOURCE_BULLETS:
-               {
-                       limit = g_pickup_nails_max;
-                       break;
-               }
-               case RESOURCE_ROCKETS:
-               {
-                       limit = g_pickup_rockets_max;
-                       break;
-               }
-               case RESOURCE_CELLS:
-               {
-                       limit = g_pickup_cells_max;
-                       break;
-               }
-               case RESOURCE_PLASMA:
-               {
-                       limit = g_pickup_plasma_max;
-                       break;
-               }
-               case RESOURCE_FUEL:
-               {
-                       limit = g_pickup_fuel_max;
-                       break;
-               }
-               default:
-               {
-                       error("GetResourceLimit: Invalid resource type.");
-                       return 0;
-               }
-       }
-       MUTATOR_CALLHOOK(GetResourceLimit, resource_type, limit);
-       limit = M_ARGV(1, float);
-       if (limit > RESOURCE_AMOUNT_HARD_LIMIT)
-       {
-               limit = RESOURCE_AMOUNT_HARD_LIMIT
-       }
-       return limit;
-}
-
-void GivePlayerResource(entity player, int resource_type, float amount)
-{
-       if (amount == 0)
-       {
-               return;
-       }
-       bool forbid = MUTATOR_CALLHOOK(GivePlayerResource, player, resource_type,
-               amount);
-       if (forbid)
+       if (num_weapons == 0)
        {
                return;
        }
-       resource_type = M_ARGV(1, int);
-       amount = M_ARGV(2, float);
-       .float resource_property = GetResourceProperty(resource_type);
-       float max_amount = GetResourceLimit(resource_type);
-       player.(resource_property) = bound(player.(resource_property),
-               player.(resource_property) + amount, max_amount);
-       switch (resource_type)
+       int num_potential_weapons = tokenize_console(weapon_names);
+       for (int give_attempt = 0; give_attempt < num_weapons; ++give_attempt)
        {
-               case RESOURCE_HEALTH:
+               RandomSelection_Init();
+               for (int weapon_index = 0; weapon_index < num_potential_weapons;
+                       ++weapon_index)
                {
-                       player.pauserothealth_finished = max(player.pauserothealth_finished,
-                               time + autocvar_g_balance_pause_health_rot);
-                       return;
+                       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;
+                               }
+                       });
                }
-               case RESOURCE_ARMOR:
+               if (RandomSelection_chosen_ent == NULL)
                {
-                       player.pauserotarmor_finished = max(player.pauserotarmor_finished,
-                               time + autocvar_g_balance_pause_armor_rot);
                        return;
                }
-               case RESOURCE_FUEL:
+               receiver.weapons |= RandomSelection_chosen_ent.m_wepset;
+               if (RandomSelection_chosen_ent.ammo_type == RESOURCE_NONE)
                {
-                       player.pauserotfuel_finished = max(player.pauserotfuel_finished,
-                               time + autocvar_g_balance_pause_fuel_rot);
-                       return;
+                       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));
        }
 }
 
-void GivePlayerResourceViaProperty(entity player, .float resource_property,
-       float amount)
-{
-       GivePlayerResource(player, GetResourceType(resource_property), amount);
-}
-
-void GivePlayerHealth(entity player, float amount)
-{
-       GivePlayerResource(player, RESOURCE_HEALTH, amount);
-}
-
-void GivePlayerArmor(entity player, float amount)
-{
-       GivePlayerResource(player, RESOURCE_ARMOR, amount);
-}
-
-void GivePlayerFuel(entity player, float amount)
-{
-       GivePlayerResource(player, RESOURCE_FUEL, amount);
-}
-
-float Item_GiveAmmoTo(entity item, entity player, .float ammotype, float ammomax)
+float Item_GiveAmmoTo(entity item, entity player, int resource_type, float ammomax)
 {
-       if (!item.(ammotype))
+       float amount = GetResourceAmount(item, resource_type);
+       if (amount == 0)
+       {
                return false;
-
+       }
+       float player_amount = GetResourceAmount(player, resource_type);
        if (item.spawnshieldtime)
        {
-               if ((player.(ammotype) < ammomax) || item.pickup_anyway > 0)
+               if ((player_amount >= ammomax) && (item.pickup_anyway <= 0))
                {
-                       float amount = item.(ammotype);
-                       if ((player.(ammotype) + amount) > ammomax)
-                       {
-                               amount = ammomax - player.(ammotype);
-                       }
-                       GivePlayerResourceViaProperty(player, ammotype, amount);
-                       return true;
+                       return false;
                }
+               GiveResourceWithLimit(player, resource_type, amount, ammomax);
+               return true;
        }
-       else if(g_weapon_stay == 2)
+       if (g_weapon_stay != 2)
        {
-               float mi = min(item.(ammotype), ammomax);
-               if (player.(ammotype) < mi)
-               {
-                       GivePlayerResourceViaProperty(player, ammotype, mi -
-                               player.(ammotype));
-               }
-               return true;
+               return false;
        }
-       return false;
+       GiveResourceWithLimit(player, resource_type, amount, min(amount, ammomax));
+       return true;
 }
 
 float Item_GiveTo(entity item, entity player)
@@ -895,14 +778,14 @@ float Item_GiveTo(entity item, entity player)
                        }
                }
        }
-       pickedup |= Item_GiveAmmoTo(item, player, health, item.max_health);
-       pickedup |= Item_GiveAmmoTo(item, player, armorvalue, item.max_armorvalue);
-       pickedup |= Item_GiveAmmoTo(item, player, ammo_shells, g_pickup_shells_max);
-       pickedup |= Item_GiveAmmoTo(item, player, ammo_nails, g_pickup_nails_max);
-       pickedup |= Item_GiveAmmoTo(item, player, ammo_rockets, g_pickup_rockets_max);
-       pickedup |= Item_GiveAmmoTo(item, player, ammo_cells, g_pickup_cells_max);
-       pickedup |= Item_GiveAmmoTo(item, player, ammo_plasma, g_pickup_plasma_max);
-       pickedup |= Item_GiveAmmoTo(item, player, ammo_fuel, g_pickup_fuel_max);
+       pickedup |= Item_GiveAmmoTo(item, player, RESOURCE_HEALTH, item.max_health);
+       pickedup |= Item_GiveAmmoTo(item, player, RESOURCE_ARMOR, item.max_armorvalue);
+       pickedup |= Item_GiveAmmoTo(item, player, RESOURCE_SHELLS, g_pickup_shells_max);
+       pickedup |= Item_GiveAmmoTo(item, player, RESOURCE_BULLETS, g_pickup_nails_max);
+       pickedup |= Item_GiveAmmoTo(item, player, RESOURCE_ROCKETS, g_pickup_rockets_max);
+       pickedup |= Item_GiveAmmoTo(item, player, RESOURCE_CELLS, g_pickup_cells_max);
+       pickedup |= Item_GiveAmmoTo(item, player, RESOURCE_PLASMA, g_pickup_plasma_max);
+       pickedup |= Item_GiveAmmoTo(item, player, RESOURCE_FUEL, g_pickup_fuel_max);
        if (item.itemdef.instanceOfWeaponPickup)
        {
                WepSet w;
@@ -959,8 +842,6 @@ float Item_GiveTo(entity item, entity player)
                player.superweapons_finished = max(player.superweapons_finished, time) + item.superweapons_finished;
        }
 
-LABEL(skip)
-
        // always eat teamed entities
        if(item.team)
                pickedup = true;
@@ -996,9 +877,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())
                {
@@ -1023,17 +903,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;
@@ -1050,29 +929,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)
+       {
+               return;
+       }
+       entity e;
+       if (this.team)
        {
-               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)
@@ -1080,16 +970,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);
        }
 }
 
@@ -1194,14 +1087,14 @@ float ammo_pickupevalfunc(entity player, entity item)
                        if(!(player.weapons & (it.m_wepset)))
                                continue;
 
-                       switch(it.ammo_field)
+                       switch(it.ammo_type)
                        {
-                               case ammo_shells:  need_shells  = true; break;
-                               case ammo_nails:   need_nails   = true; break;
-                               case ammo_rockets: need_rockets = true; break;
-                               case ammo_cells:   need_cells   = true; break;
-                               case ammo_plasma:  need_plasma  = true; break;
-                               case ammo_fuel:    need_fuel    = true; break;
+                               case RESOURCE_SHELLS:  need_shells  = true; break;
+                               case RESOURCE_BULLETS: need_nails   = true; break;
+                               case RESOURCE_ROCKETS: need_rockets = true; break;
+                               case RESOURCE_CELLS:   need_cells   = true; break;
+                               case RESOURCE_PLASMA:  need_plasma  = true; break;
+                               case RESOURCE_FUEL:    need_fuel    = true; break;
                        }
                });
                rating = item.bot_pickupbasevalue;
@@ -1321,11 +1214,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")
@@ -1335,7 +1226,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);
@@ -1450,7 +1341,7 @@ void _StartItem(entity this, entity def, float defaultrespawntime, float default
 
        if(def.instanceOfWeaponPickup)
        {
-               if (this.classname != "droppedweapon") // if dropped, colormap is already set up nicely
+               if (!Item_IsLoot(this)) // if dropped, colormap is already set up nicely
                        this.colormap = 1024; // color shirt=0 pants=0 grey
                else
                        this.gravity = 1;
@@ -1486,6 +1377,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,
@@ -1542,114 +1440,9 @@ 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")
+       if(Item_IsLoot(actor))
        {
                EXACTTRIGGER_TOUCH(this, trigger);
                delete(actor);
@@ -1664,7 +1457,7 @@ void target_items_use(entity this, entity actor, entity trigger)
                EXACTTRIGGER_TOUCH(this, trigger);
        }
 
-       IL_EACH(g_items, it.enemy == actor && it.classname == "droppedweapon",
+       IL_EACH(g_items, it.enemy == actor && Item_IsLoot(it),
        {
                delete(it);
        });
@@ -1786,31 +1579,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;