]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Merge branch 'master' into Lyberta/RandomItems
authorLyberta <lyberta@lyberta.net>
Thu, 5 Oct 2017 13:23:49 +0000 (16:23 +0300)
committerLyberta <lyberta@lyberta.net>
Thu, 5 Oct 2017 13:23:49 +0000 (16:23 +0300)
40 files changed:
mutators.cfg
qcsrc/common/items/item/ammo.qh
qcsrc/common/mutators/mutator/_mod.inc
qcsrc/common/mutators/mutator/_mod.qh
qcsrc/common/mutators/mutator/instagib/items.qh
qcsrc/common/mutators/mutator/instagib/sv_instagib.qc
qcsrc/common/mutators/mutator/instagib/sv_instagib.qh
qcsrc/common/mutators/mutator/overkill/sv_overkill.qc
qcsrc/common/mutators/mutator/random_items/_mod.inc [new file with mode: 0644]
qcsrc/common/mutators/mutator/random_items/_mod.qh [new file with mode: 0644]
qcsrc/common/mutators/mutator/random_items/sv_random_items.qc [new file with mode: 0644]
qcsrc/common/t_items.qc
qcsrc/common/t_items.qh
qcsrc/common/weapons/weapon/arc.qh
qcsrc/common/weapons/weapon/blaster.qh
qcsrc/common/weapons/weapon/crylink.qh
qcsrc/common/weapons/weapon/devastator.qh
qcsrc/common/weapons/weapon/electro.qh
qcsrc/common/weapons/weapon/fireball.qh
qcsrc/common/weapons/weapon/hagar.qh
qcsrc/common/weapons/weapon/hlac.qh
qcsrc/common/weapons/weapon/hook.qh
qcsrc/common/weapons/weapon/machinegun.qh
qcsrc/common/weapons/weapon/minelayer.qh
qcsrc/common/weapons/weapon/mortar.qh
qcsrc/common/weapons/weapon/porto.qh
qcsrc/common/weapons/weapon/rifle.qh
qcsrc/common/weapons/weapon/seeker.qh
qcsrc/common/weapons/weapon/shockwave.qh
qcsrc/common/weapons/weapon/shotgun.qh
qcsrc/common/weapons/weapon/tuba.qh
qcsrc/common/weapons/weapon/vaporizer.qh
qcsrc/common/weapons/weapon/vortex.qh
qcsrc/server/_mod.inc
qcsrc/server/_mod.qh
qcsrc/server/compat/quake3.qc
qcsrc/server/compat/wop.qc
qcsrc/server/items.qc [new file with mode: 0644]
qcsrc/server/items.qh [new file with mode: 0644]
qcsrc/server/mutators/events.qh

index c57088dd92910c1e1915d8bd61ba31918b3eb085..9b50a64767cdf357bf1eb98227dde2b5271361c5 100644 (file)
@@ -473,3 +473,149 @@ set g_dynamic_handicap_scale 0.2 "The scale of the handicap. Larger values mean
 set g_dynamic_handicap_exponent 1 "The exponent used to calculate handicap. 1 means linear scale. Values more than 1 mean stronger non-linear handicap. Values less than 1 mean weaker non-linear handicap"
 set g_dynamic_handicap_min 0 "The minimum value of the handicap."
 set g_dynamic_handicap_max 0 "The maximum value of the handicap."
+
+// ==============
+//  random items
+// ==============
+set g_random_items 0 "Whether to enable random items."
+set g_random_items_replace_health_small "random" "Classnames to replace small health with."
+set g_random_items_replace_health_medium "random" "Classnames to replace medium health with."
+set g_random_items_replace_health_big "random" "Classnames to replace big health with."
+set g_random_items_replace_health_mega "random" "Classnames to replace mega health with."
+set g_random_items_replace_armor_small "random" "Classnames to replace small armor with."
+set g_random_items_replace_armor_medium "random" "Classnames to replace medium armor with."
+set g_random_items_replace_armor_big "random" "Classnames to replace big armor with."
+set g_random_items_replace_armor_mega "random" "Classnames to replace mega armor with."
+set g_random_items_replace_item_shells "random" "Classnames to replace shells with."
+set g_random_items_replace_item_bullets "random" "Classnames to replace bullets with."
+set g_random_items_replace_item_rockets "random" "Classnames to replace rockets with."
+set g_random_items_replace_item_cells "random" "Classnames to replace cells with."
+set g_random_items_replace_item_plasma "random" "Classnames to replace plasma with."
+set g_random_items_replace_item_fuel "random" "Classnames to replace fuel with."
+set g_random_items_replace_weapon_blaster "random" "Classnames to replace blaster with."
+set g_random_items_replace_weapon_shotgun "random" "Classnames to replace shotgun with."
+set g_random_items_replace_weapon_machinegun "random" "Classnames to replace machinegun with."
+set g_random_items_replace_weapon_mortar "random" "Classnames to replace mortar with."
+set g_random_items_replace_weapon_electro "random" "Classnames to replace electro with."
+set g_random_items_replace_weapon_crylink "random" "Classnames to replace crylink with."
+set g_random_items_replace_weapon_vortex "random" "Classnames to replace vortex with."
+set g_random_items_replace_weapon_hagar "random" "Classnames to replace hagar with."
+set g_random_items_replace_weapon_devastator "random" "Classnames to replace devastator with."
+set g_random_items_replace_weapon_shockwave "random" "Classnames to replace shockwave with."
+set g_random_items_replace_weapon_arc "random" "Classnames to replace arc with."
+set g_random_items_replace_weapon_hook "random" "Classnames to replace hook with."
+set g_random_items_replace_weapon_tuba "random" "Classnames to replace tuba with."
+set g_random_items_replace_weapon_porto "random" "Classnames to replace port-o-launch with."
+set g_random_items_replace_weapon_fireball "random" "Classnames to replace fireball with."
+set g_random_items_replace_weapon_minelayer "random" "Classnames to replace mine layer with."
+set g_random_items_replace_weapon_hlac "random" "Classnames to replace HLAC with."
+set g_random_items_replace_weapon_rifle "random" "Classnames to replace rifle with."
+set g_random_items_replace_weapon_seeker "random" "Classnames to replace TAG seeker with."
+set g_random_items_replace_weapon_vaporizer "random" "Classnames to replace vaporizer with."
+set g_random_items_replace_item_strength "random" "Classnames to replace strength with."
+set g_random_items_replace_item_shield "random" "Classnames to replace shield with."
+set g_random_items_replace_item_fuel_regen "random" "Classnames to replace fuel regeneration with."
+set g_random_items_replace_item_jetpack "random" "Classnames to replace jetpack with."
+set g_random_items_replace_item_vaporizer_cells "random" "Classnames to replace vaporizer cells with."
+set g_random_items_replace_item_invisibility "random" "Classnames to replace invisibility with."
+set g_random_items_replace_item_extralife "random" "Classnames to replace extra life with."
+set g_random_items_replace_item_speed "random" "Classnames to replace speed with."
+set g_random_items_health_probability 1 "Probability of random health items spawning in the map."
+set g_random_items_armor_probability 1 "Probability of random armor items spawning in the map."
+set g_random_items_resource_probability 1 "Probability of random ammo items spawning in the map."
+set g_random_items_weapon_probability 1 "Probability of random weapons spawning in the map."
+set g_random_items_powerup_probability 0.175 "Probability of random powerups spawning in the map."
+set g_random_items_health_small_probability 10 "Probability of random small health spawning in the map."
+set g_random_items_health_medium_probability 4 "Probability of random medium health spawning in the map."
+set g_random_items_health_big_probability 2 "Probability of random big health spawning in the map."
+set g_random_items_health_mega_probability 1 "Probability of random mega health spawning in the map."
+set g_random_items_armor_small_probability 10 "Probability of random small armor spawning in the map."
+set g_random_items_armor_medium_probability 4 "Probability of random medium armor spawning in the map."
+set g_random_items_armor_big_probability 2 "Probability of random big armor spawning in the map."
+set g_random_items_armor_mega_probability 1 "Probability of random mega armor spawning in the map."
+set g_random_items_resource_shells_probability 1 "Probability of random shells spawning in the map."
+set g_random_items_resource_bullets_probability 1 "Probability of random bullets spawning in the map."
+set g_random_items_resource_rockets_probability 1 "Probability of random rockets spawning in the map."
+set g_random_items_resource_cells_probability 1 "Probability of random cells spawning in the map."
+set g_random_items_resource_plasma_probability 0 "Probability of random plasma spawning in the map."
+set g_random_items_resource_fuel_probability 0 "Probability of random fuel spawning in the map."
+set g_random_items_weapon_blaster_probability 0 "Probability of random blaster spawning in the map."
+set g_random_items_weapon_shotgun_probability 0 "Probability of random shotgun spawning in the map."
+set g_random_items_weapon_machinegun_probability 1 "Probability of random machinegun spawning in the map."
+set g_random_items_weapon_mortar_probability 1 "Probability of random mortar spawning in the map."
+set g_random_items_weapon_electro_probability 1 "Probability of random electro spawning in the map."
+set g_random_items_weapon_crylink_probability 1 "Probability of random crylink spawning in the map."
+set g_random_items_weapon_vortex_probability 1 "Probability of random vortex spawning in the map."
+set g_random_items_weapon_hagar_probability 1 "Probability of random hagar spawning in the map."
+set g_random_items_weapon_devastator_probability 1 "Probability of random devastator spawning in the map."
+set g_random_items_weapon_shockwave_probability 0 "Probability of random shockwave spawning in the map."
+set g_random_items_weapon_arc_probability 0 "Probability of random arc spawning in the map."
+set g_random_items_weapon_hook_probability 0 "Probability of random hook spawning in the map."
+set g_random_items_weapon_tuba_probability 0 "Probability of random tuba spawning in the map."
+set g_random_items_weapon_porto_probability 0 "Probability of random port-o-launch spawning in the map."
+set g_random_items_weapon_fireball_probability 0 "Probability of random fireball spawning in the map."
+set g_random_items_weapon_minelayer_probability 0 "Probability of random mine layer spawning in the map."
+set g_random_items_weapon_hlac_probability 0 "Probability of random HLAC spawning in the map."
+set g_random_items_weapon_rifle_probability 0 "Probability of random rifle spawning in the map."
+set g_random_items_weapon_seeker_probability 0 "Probability of random TAG seeker spawning in the map."
+set g_random_items_weapon_vaporizer_probability 0 "Probability of random vaporizer spawning in the map."
+set g_random_items_strength_probability 1 "Probability of random strength spawning in the map."
+set g_random_items_shield_probability 1 "Probability of random shield spawning in the map."
+set g_random_items_fuel_regen_probability 0 "Probability of random fuel regeneration spawning in the map."
+set g_random_items_jetpack_probability 0 "Probability of random jetpack spawning in the map."
+set g_random_items_vaporizer_cells_probability 20 "Probability of random vaporizer cells spawning in the map."
+set g_random_items_invisibility_probability 1 "Probability of random invisibility spawning in the map."
+set g_random_items_extralife_probability 1 "Probability of random extra life spawning in the map."
+set g_random_items_speed_probability 1 "Probability of random speed spawning in the map."
+set g_random_loot 0 "Whether to enable random loot."
+set g_random_loot_min 0 "Minimum amount of loot items."
+set g_random_loot_max 4 "Minimum amount of loot items."
+set g_random_loot_time 10 "Amount of time the loot will stay."
+set g_random_loot_spread 200 "How far can loot be thrown."
+set g_random_loot_health_probability 1 "Probability of random health items spawning as loot."
+set g_random_loot_armor_probability 1 "Probability of random armor items spawning as loot."
+set g_random_loot_resource_probability 1 "Probability of random ammo items spawning as loot."
+set g_random_loot_weapon_probability 1 "Probability of random weapons spawning as loot."
+set g_random_loot_powerup_probability 0.2 "Probability of random powerups spawning as loot."
+set g_random_loot_health_small_probability 4 "Probability of random small health spawning as loot."
+set g_random_loot_health_medium_probability 3 "Probability of random medium health spawning as loot."
+set g_random_loot_health_big_probability 2 "Probability of random big health spawning as loot."
+set g_random_loot_health_mega_probability 1 "Probability of random mega health spawning as loot."
+set g_random_loot_armor_small_probability 4 "Probability of random small armor spawning as loot."
+set g_random_loot_armor_medium_probability 3 "Probability of random medium armor spawning as loot."
+set g_random_loot_armor_big_probability 2 "Probability of random big armor spawning as loot."
+set g_random_loot_armor_mega_probability 1 "Probability of random mega armor spawning as loot."
+set g_random_loot_resource_shells_probability 1 "Probability of random shells spawning as loot."
+set g_random_loot_resource_bullets_probability 1 "Probability of random bullets spawning as loot."
+set g_random_loot_resource_rockets_probability 1 "Probability of random rockets spawning as loot."
+set g_random_loot_resource_cells_probability 1 "Probability of random cells spawning as loot."
+set g_random_loot_resource_plasma_probability 0 "Probability of random plasma spawning as loot."
+set g_random_loot_resource_fuel_probability 0 "Probability of random fuel spawning as loot."
+set g_random_loot_weapon_blaster_probability 0 "Probability of random blaster spawning as loot."
+set g_random_loot_weapon_shotgun_probability 0 "Probability of random shotgun spawning as loot."
+set g_random_loot_weapon_machinegun_probability 1 "Probability of random machinegun spawning as loot."
+set g_random_loot_weapon_mortar_probability 1 "Probability of random mortar spawning as loot."
+set g_random_loot_weapon_electro_probability 1 "Probability of random electro spawning as loot."
+set g_random_loot_weapon_crylink_probability 1 "Probability of random crylink spawning as loot."
+set g_random_loot_weapon_vortex_probability 1 "Probability of random vortex spawning as loot."
+set g_random_loot_weapon_hagar_probability 1 "Probability of random hagar spawning as loot."
+set g_random_loot_weapon_devastator_probability 1 "Probability of random devastator spawning as loot."
+set g_random_loot_weapon_shockwave_probability 0 "Probability of random shockwave spawning as loot."
+set g_random_loot_weapon_arc_probability 0 "Probability of random arc spawning as loot."
+set g_random_loot_weapon_hook_probability 0 "Probability of random hook spawning as loot."
+set g_random_loot_weapon_tuba_probability 0 "Probability of random tuba spawning as loot."
+set g_random_loot_weapon_porto_probability 0 "Probability of random port-o-launch spawning as loot."
+set g_random_loot_weapon_fireball_probability 0 "Probability of random fireball spawning as loot."
+set g_random_loot_weapon_minelayer_probability 0 "Probability of random mine layer spawning as loot."
+set g_random_loot_weapon_hlac_probability 0 "Probability of random HLAC spawning as loot."
+set g_random_loot_weapon_rifle_probability 0 "Probability of random rifle spawning as loot."
+set g_random_loot_weapon_seeker_probability 0 "Probability of random TAG seeker spawning as loot."
+set g_random_loot_weapon_vaporizer_probability 0 "Probability of random vaporizer spawning as loot."
+set g_random_loot_strength_probability 1 "Probability of random strength spawning as loot."
+set g_random_loot_shield_probability 1 "Probability of random shield spawning as loot."
+set g_random_loot_fuel_regen_probability 0 "Probability of random fuel regeneration spawning as loot."
+set g_random_loot_jetpack_probability 0 "Probability of random jetpack spawning as loot."
+set g_random_loot_vaporizer_cells_probability 20 "Probability of random vaporizer cells spawning as loot."
+set g_random_loot_invisibility_probability 1 "Probability of random invisibility spawning as loot."
+set g_random_loot_extralife_probability 1 "Probability of random extra life spawning as loot."
+set g_random_loot_speed_probability 1 "Probability of random speed spawning as loot."
index 20963928526a12ddfe94313004fffe946ca89b8c..b3361d248c852db75ace43b232885c5bf460f6ff 100644 (file)
@@ -1,6 +1,10 @@
 #pragma once
 
 #include "pickup.qh"
+#ifdef SVQC
+    #include <common/t_items.qh>
+#endif
+
 #ifdef SVQC
 PROPERTY(float, g_pickup_ammo_anyway);
 #endif
@@ -14,9 +18,6 @@ CLASS(Ammo, Pickup)
 #endif
 ENDCLASS(Ammo)
 
-#ifdef SVQC
-    #include <common/t_items.qh>
-#endif
 
 #ifdef GAMEQC
 MODEL(Bullets_ITEM, Item_Model("a_bullets.mdl"));
index eeb93ba5e83f7cb9252274e397c994bf9e93a73e..59b2c117d2cb63e705726ce6e997c4e46b359775 100644 (file)
@@ -25,6 +25,7 @@
 #include <common/mutators/mutator/physical_items/_mod.inc>
 #include <common/mutators/mutator/pinata/_mod.inc>
 #include <common/mutators/mutator/random_gravity/_mod.inc>
+#include <common/mutators/mutator/random_items/_mod.inc>
 #include <common/mutators/mutator/rocketflying/_mod.inc>
 #include <common/mutators/mutator/rocketminsta/_mod.inc>
 #include <common/mutators/mutator/running_guns/_mod.inc>
index 956c0d97536fbfeaddc4d4b8b1728ce147d09bc5..b1c627fb6d76d3c48b75a31198a10fa7453c23cb 100644 (file)
@@ -25,6 +25,7 @@
 #include <common/mutators/mutator/physical_items/_mod.qh>
 #include <common/mutators/mutator/pinata/_mod.qh>
 #include <common/mutators/mutator/random_gravity/_mod.qh>
+#include <common/mutators/mutator/random_items/_mod.qh>
 #include <common/mutators/mutator/rocketflying/_mod.qh>
 #include <common/mutators/mutator/rocketminsta/_mod.qh>
 #include <common/mutators/mutator/running_guns/_mod.qh>
index e80f36e1a087542eb7d3ee0c06f5c493c7902d0c..91671efcb2527a65b6055dcfcd232fc2a4526c73 100644 (file)
@@ -27,7 +27,7 @@ REGISTER_ITEM(VaporizerCells, Ammo) {
     this.m_model                =   MDL_VaporizerCells_ITEM;
     this.m_sound                =   SND_VaporizerCells;
 #endif
-    this.netname                =   "minst_cells";
+    this.netname                =   "vaporizer_cells";
     this.m_name                 =   "Vaporizer Ammo";
     this.m_icon                 =   "ammo_supercells";
 #ifdef SVQC
index 1561dc10db9a326acf932de70df86365e179bd4f..c62b04fcbd2b04d1f1da6c0598e68902063446a1 100644 (file)
@@ -19,7 +19,7 @@ float autocvar_g_instagib_speed_highspeed;
 
 REGISTER_MUTATOR(mutator_instagib, autocvar_g_instagib && !g_nexball);
 
-spawnfunc(item_minst_cells)
+spawnfunc(item_vaporizer_cells)
 {
        if (!g_instagib) { delete(this); return; }
        StartItem(this, ITEM_VaporizerCells);
@@ -377,13 +377,13 @@ MUTATOR_HOOKFUNCTION(mutator_instagib, SetWeaponArena)
 
 void replace_with_insta_cells(entity item)
 {
-       entity e = spawn();
+       entity e = new(item_vaporizer_cells);
        setorigin(e, item.origin);
        e.noalign = item.noalign;
        e.cnt = item.cnt;
        e.team = item.team;
        e.spawnfunc_checked = true;
-       spawnfunc_item_minst_cells(e);
+       spawnfunc_item_vaporizer_cells(e);
 }
 
 MUTATOR_HOOKFUNCTION(mutator_instagib, FilterItem)
@@ -439,7 +439,7 @@ MUTATOR_HOOKFUNCTION(mutator_instagib, FilterItem)
                return false;
 
        float cells = GetResourceAmount(item, RESOURCE_CELLS);
-       if(cells > autocvar_g_instagib_ammo_drop && item.classname != "item_minst_cells")
+       if(cells > autocvar_g_instagib_ammo_drop && item.classname != "item_vaporizer_cells")
                SetResourceAmount(item, RESOURCE_CELLS, autocvar_g_instagib_ammo_drop);
 
        if(cells && !item.weapon)
@@ -515,11 +515,20 @@ MUTATOR_HOOKFUNCTION(mutator_instagib, OnEntityPreSpawn)
 
        float r = random();
        if (r < 0.3)
+       {
+               e.classname = "item_invisibility";
                setthink(e, instagib_invisibility);
+       }
        else if (r < 0.6)
+       {
+               e.classname = "item_extralife";
                setthink(e, instagib_extralife);
+       }
        else
+       {
+               e.classname = "item_speed";
                setthink(e, instagib_speed);
+       }
 
        e.nextthink = time + 0.1;
        e.spawnflags = ent.spawnflags;
index 4c6d20b1293c7f317ab89d8c5f61ac89a2088ea1..051c93525afcddbaf621e42448e9eb09539c0456 100644 (file)
@@ -3,3 +3,8 @@
 #include "items.qh"
 
 float autocvar_g_instagib_invis_alpha;
+
+spawnfunc(item_vaporizer_cells);
+void instagib_invisibility(entity this);
+void instagib_extralife(entity this);
+void instagib_speed(entity this);
index b47e587511643e3076e172835052c16787d3079d..ea541ce440750283b4325eacdaedf3386a70ae74 100644 (file)
@@ -61,20 +61,10 @@ MUTATOR_HOOKFUNCTION(ok, Damage_Calculate, CBC_ORDER_LAST)
 
 void ok_DropItem(entity this, entity targ)
 {
-       entity e = new(droppedweapon); // hax
+       entity e = spawn();
        e.ok_item = true;
-       e.noalign = true;
-       e.pickup_anyway = true;
-       e.spawnfunc_checked = true;
-       spawnfunc_item_armor_small(e);
-       if (!wasfreed(e)) { // might have been blocked by a mutator
-        set_movetype(e, MOVETYPE_TOSS);
-        e.gravity = 1;
-        e.reset = SUB_Remove;
-        setorigin(e, this.origin + '0 0 32');
-        e.velocity = '0 0 200' + normalize(targ.origin - this.origin) * 500;
-        SUB_SetFade(e, time + 5, 1);
-       }
+       Item_InitializeLoot(e, "item_armor_small", this.origin + '0 0 32',
+               '0 0 200' + normalize(targ.origin - this.origin) * 500, 5);
 }
 
 MUTATOR_HOOKFUNCTION(ok, PlayerDies)
diff --git a/qcsrc/common/mutators/mutator/random_items/_mod.inc b/qcsrc/common/mutators/mutator/random_items/_mod.inc
new file mode 100644 (file)
index 0000000..191ea09
--- /dev/null
@@ -0,0 +1,4 @@
+// generated file; do not modify
+#ifdef SVQC
+    #include <common/mutators/mutator/random_items/sv_random_items.qc>
+#endif
diff --git a/qcsrc/common/mutators/mutator/random_items/_mod.qh b/qcsrc/common/mutators/mutator/random_items/_mod.qh
new file mode 100644 (file)
index 0000000..98fb481
--- /dev/null
@@ -0,0 +1 @@
+// generated file; do not modify
diff --git a/qcsrc/common/mutators/mutator/random_items/sv_random_items.qc b/qcsrc/common/mutators/mutator/random_items/sv_random_items.qc
new file mode 100644 (file)
index 0000000..10bbadd
--- /dev/null
@@ -0,0 +1,1428 @@
+/// \file
+/// \brief Source file that contains implementation of the random items mutator.
+/// \author Lyberta
+/// \copyright GNU GPLv2 or any later version.
+
+//============================ Constants ======================================
+
+enum
+{
+       RANDOM_ITEM_TYPE_HEALTH,
+       RANDOM_ITEM_TYPE_ARMOR,
+       RANDOM_ITEM_TYPE_RESOURCE,
+       RANDOM_ITEM_TYPE_WEAPON,
+       RANDOM_ITEM_TYPE_POWERUP
+};
+
+enum
+{
+       RANDOM_ITEM_SUBTYPE_HEALTH_SMALL,
+       RANDOM_ITEM_SUBTYPE_HEALTH_MEDIUM,
+       RANDOM_ITEM_SUBTYPE_HEALTH_BIG,
+       RANDOM_ITEM_SUBTYPE_HEALTH_MEGA
+};
+
+enum
+{
+       RANDOM_ITEM_SUBTYPE_ARMOR_SMALL,
+       RANDOM_ITEM_SUBTYPE_ARMOR_MEDIUM,
+       RANDOM_ITEM_SUBTYPE_ARMOR_BIG,
+       RANDOM_ITEM_SUBTYPE_ARMOR_MEGA
+};
+
+enum
+{
+       RANDOM_ITEM_SUBTYPE_RESOURCE_SHELLS,
+       RANDOM_ITEM_SUBTYPE_RESOURCE_BULLETS,
+       RANDOM_ITEM_SUBTYPE_RESOURCE_ROCKETS,
+       RANDOM_ITEM_SUBTYPE_RESOURCE_CELLS,
+       RANDOM_ITEM_SUBTYPE_RESOURCE_PLASMA,
+       RANDOM_ITEM_SUBTYPE_RESOURCE_FUEL,
+};
+
+enum
+{
+       RANDOM_ITEM_SUBTYPE_WEAPON_BLASTER,
+       RANDOM_ITEM_SUBTYPE_WEAPON_SHOTGUN,
+       RANDOM_ITEM_SUBTYPE_WEAPON_MACHINEGUN,
+       RANDOM_ITEM_SUBTYPE_WEAPON_MORTAR,
+       RANDOM_ITEM_SUBTYPE_WEAPON_ELECTRO,
+       RANDOM_ITEM_SUBTYPE_WEAPON_CRYLINK,
+       RANDOM_ITEM_SUBTYPE_WEAPON_VORTEX,
+       RANDOM_ITEM_SUBTYPE_WEAPON_HAGAR,
+       RANDOM_ITEM_SUBTYPE_WEAPON_DEVASTATOR,
+       RANDOM_ITEM_SUBTYPE_WEAPON_SHOCKWAVE,
+       RANDOM_ITEM_SUBTYPE_WEAPON_ARC,
+       RANDOM_ITEM_SUBTYPE_WEAPON_HOOK,
+       RANDOM_ITEM_SUBTYPE_WEAPON_TUBA,
+       RANDOM_ITEM_SUBTYPE_WEAPON_PORTO,
+       RANDOM_ITEM_SUBTYPE_WEAPON_FIREBALL,
+       RANDOM_ITEM_SUBTYPE_WEAPON_MINELAYER,
+       RANDOM_ITEM_SUBTYPE_WEAPON_HLAC,
+       RANDOM_ITEM_SUBTYPE_WEAPON_RIFLE,
+       RANDOM_ITEM_SUBTYPE_WEAPON_SEEKER,
+       RANDOM_ITEM_SUBTYPE_WEAPON_VAPORIZER
+};
+
+enum
+{
+       RANDOM_ITEM_SUBTYPE_POWERUP_STRENGTH,
+       RANDOM_ITEM_SUBTYPE_POWERUP_SHIELD,
+       RANDOM_ITEM_SUBTYPE_POWERUP_FUEL_REGEN,
+       RANDOM_ITEM_SUBTYPE_POWERUP_JETPACK
+};
+
+enum
+{
+       RANDOM_ITEM_SUBTYPE_INSTAGIB_VAPORIZER_CELLS,
+       RANDOM_ITEM_SUBTYPE_INSTAGIB_INVISIBILITY,
+       RANDOM_ITEM_SUBTYPE_INSTAGIB_EXTRA_LIFE,
+       RANDOM_ITEM_SUBTYPE_INSTAGIB_SPEED
+};
+
+//======================= Global variables ====================================
+
+bool autocvar_g_random_items; ///< Whether to enable random items.
+
+// Replace cvars
+
+/// \brief Classnames to replace small health with.
+string autocvar_g_random_items_replace_health_small;
+/// \brief Classnames to replace medium health with.
+string autocvar_g_random_items_replace_health_medium;
+/// \brief Classnames to replace big health with.
+string autocvar_g_random_items_replace_health_big;
+/// \brief Classnames to replace mega health with.
+string autocvar_g_random_items_replace_health_mega;
+
+/// \brief Classnames to replace small armor with.
+string autocvar_g_random_items_replace_armor_small;
+/// \brief Classnames to replace medium armor with.
+string autocvar_g_random_items_replace_armor_medium;
+/// \brief Classnames to replace big armor with.
+string autocvar_g_random_items_replace_armor_big;
+/// \brief Classnames to replace mega armor with.
+string autocvar_g_random_items_replace_armor_mega;
+
+/// \brief Classnames to replace shells with.
+string autocvar_g_random_items_replace_item_shells;
+/// \brief Classnames to replace bullets with.
+string autocvar_g_random_items_replace_item_bullets;
+/// \brief Classnames to replace rockets with.
+string autocvar_g_random_items_replace_item_rockets;
+/// \brief Classnames to replace cells with.
+string autocvar_g_random_items_replace_item_cells;
+/// \brief Classnames to replace plasma with.
+string autocvar_g_random_items_replace_item_plasma;
+/// \brief Classnames to replace fuel with.
+string autocvar_g_random_items_replace_item_fuel;
+
+/// \brief Classnames to replace blaster with.
+string autocvar_g_random_items_replace_weapon_blaster;
+/// \brief Classnames to replace shotgun with.
+string autocvar_g_random_items_replace_weapon_shotgun;
+/// \brief Classnames to replace machinegun with.
+string autocvar_g_random_items_replace_weapon_machinegun;
+/// \brief Classnames to replace mortar with.
+string autocvar_g_random_items_replace_weapon_mortar;
+/// \brief Classnames to replace electro with.
+string autocvar_g_random_items_replace_weapon_electro;
+/// \brief Classnames to replace crylink with.
+string autocvar_g_random_items_replace_weapon_crylink;
+/// \brief Classnames to replace vortex with.
+string autocvar_g_random_items_replace_weapon_vortex;
+/// \brief Classnames to replace hagar with.
+string autocvar_g_random_items_replace_weapon_hagar;
+/// \brief Classnames to replace devastator with.
+string autocvar_g_random_items_replace_weapon_devastator;
+/// \brief Classnames to replace shockwave with.
+string autocvar_g_random_items_replace_weapon_shockwave;
+/// \brief Classnames to replace arc with.
+string autocvar_g_random_items_replace_weapon_arc;
+/// \brief Classnames to replace hook with.
+string autocvar_g_random_items_replace_weapon_hook;
+/// \brief Classnames to replace tuba with.
+string autocvar_g_random_items_replace_weapon_tuba;
+/// \brief Classnames to replace port-o-launch with.
+string autocvar_g_random_items_replace_weapon_porto;
+/// \brief Classnames to replace fireball with.
+string autocvar_g_random_items_replace_weapon_fireball;
+/// \brief Classnames to replace mine layer with.
+string autocvar_g_random_items_replace_weapon_minelayer;
+/// \brief Classnames to replace HLAC with.
+string autocvar_g_random_items_replace_weapon_hlac;
+/// \brief Classnames to replace rifle with.
+string autocvar_g_random_items_replace_weapon_rifle;
+/// \brief Classnames to replace TAG seeker with.
+string autocvar_g_random_items_replace_weapon_seeker;
+/// \brief Classnames to replace vaporizer with.
+string autocvar_g_random_items_replace_weapon_vaporizer;
+
+/// \brief Classnames to replace strength with.
+string autocvar_g_random_items_replace_item_strength;
+/// \brief Classnames to replace shield with.
+string autocvar_g_random_items_replace_item_shield;
+/// \brief Classnames to replace fuel regeneration with.
+string autocvar_g_random_items_replace_item_fuel_regen;
+/// \brief Classnames to replace jetpack with.
+string autocvar_g_random_items_replace_item_jetpack;
+
+/// \brief Classnames to replace vaporizer cells with.
+string autocvar_g_random_items_replace_item_vaporizer_cells;
+/// \brief Classnames to replace invisibility with.
+string autocvar_g_random_items_replace_item_invisibility;
+/// \brief Classnames to replace extra life with.
+string autocvar_g_random_items_replace_item_extralife;
+/// \brief Classnames to replace speed with.
+string autocvar_g_random_items_replace_item_speed;
+
+// Map probability cvars
+
+/// \brief Probability of random health items spawning in the map.
+float autocvar_g_random_items_health_probability;
+/// \brief Probability of random armor items spawning in the map.
+float autocvar_g_random_items_armor_probability;
+/// \brief Probability of random resource items spawning in the map.
+float autocvar_g_random_items_resource_probability;
+/// \brief Probability of random weapons spawning in the map.
+float autocvar_g_random_items_weapon_probability;
+/// \brief Probability of random powerups spawning in the map.
+float autocvar_g_random_items_powerup_probability;
+
+/// \brief Probability of random small health spawning in the map.
+float autocvar_g_random_items_health_small_probability;
+/// \brief Probability of random medium health spawning in the map.
+float autocvar_g_random_items_health_medium_probability;
+/// \brief Probability of random big health spawning in the map.
+float autocvar_g_random_items_health_big_probability;
+/// \brief Probability of random mega health spawning in the map.
+float autocvar_g_random_items_health_mega_probability;
+
+/// \brief Probability of random small armor spawning in the map.
+float autocvar_g_random_items_armor_small_probability;
+/// \brief Probability of random medium armor.spawning in the map.
+float autocvar_g_random_items_armor_medium_probability;
+/// \brief Probability of random big armor spawning in the map.
+float autocvar_g_random_items_armor_big_probability;
+/// \brief Probability of random mega armor spawning in the map.
+float autocvar_g_random_items_armor_mega_probability;
+
+/// \brief Probability of random shells spawning in the map.
+float autocvar_g_random_items_resource_shells_probability;
+/// \brief Probability of random bullets spawning in the map.
+float autocvar_g_random_items_resource_bullets_probability;
+/// \brief Probability of random rockets spawning in the map.
+float autocvar_g_random_items_resource_rockets_probability;
+/// \brief Probability of random cells spawning in the map.
+float autocvar_g_random_items_resource_cells_probability;
+/// \brief Probability of random plasma spawning in the map.
+float autocvar_g_random_items_resource_plasma_probability;
+/// \brief Probability of random fuel spawning in the map.
+float autocvar_g_random_items_resource_fuel_probability;
+
+/// \brief Probability of random blaster spawning in the map.
+float autocvar_g_random_items_weapon_blaster_probability;
+/// \brief Probability of random shotgun spawning in the map.
+float autocvar_g_random_items_weapon_shotgun_probability;
+/// \brief Probability of random machinegun spawning in the map.
+float autocvar_g_random_items_weapon_machinegun_probability;
+/// \brief Probability of random mortar spawning in the map.
+float autocvar_g_random_items_weapon_mortar_probability;
+/// \brief Probability of random electro spawning in the map.
+float autocvar_g_random_items_weapon_electro_probability;
+/// \brief Probability of random crylink spawning in the map.
+float autocvar_g_random_items_weapon_crylink_probability;
+/// \brief Probability of random vortex spawning in the map.
+float autocvar_g_random_items_weapon_vortex_probability;
+/// \brief Probability of random hagar spawning in the map.
+float autocvar_g_random_items_weapon_hagar_probability;
+/// \brief Probability of random devastator spawning in the map.
+float autocvar_g_random_items_weapon_devastator_probability;
+/// \brief Probability of random shockwave spawning in the map.
+float autocvar_g_random_items_weapon_shockwave_probability;
+/// \brief Probability of random arc spawning in the map.
+float autocvar_g_random_items_weapon_arc_probability;
+/// \brief Probability of random hook spawning in the map.
+float autocvar_g_random_items_weapon_hook_probability;
+/// \brief Probability of random tuba spawning in the map.
+float autocvar_g_random_items_weapon_tuba_probability;
+/// \brief Probability of random port-o-launch spawning in the map.
+float autocvar_g_random_items_weapon_porto_probability;
+/// \brief Probability of random fireball spawning in the map.
+float autocvar_g_random_items_weapon_fireball_probability;
+/// \brief Probability of random mine layer spawning in the map.
+float autocvar_g_random_items_weapon_minelayer_probability;
+/// \brief Probability of random HLAC spawning in the map.
+float autocvar_g_random_items_weapon_hlac_probability;
+/// \brief Probability of random rifle spawning in the map.
+float autocvar_g_random_items_weapon_rifle_probability;
+/// \brief Probability of random TAG seeker spawning in the map.
+float autocvar_g_random_items_weapon_seeker_probability;
+/// \brief Probability of random vaporizer spawning in the map.
+float autocvar_g_random_items_weapon_vaporizer_probability;
+
+/// \brief Probability of random strength spawning in the map.
+float autocvar_g_random_items_strength_probability;
+/// \brief Probability of random shield spawning in the map.
+float autocvar_g_random_items_shield_probability;
+/// \brief Probability of random fuel regeneration spawning in the map.
+float autocvar_g_random_items_fuel_regen_probability;
+/// \brief Probability of random jetpack spawning in the map.
+float autocvar_g_random_items_jetpack_probability;
+
+/// \brief Probability of random vaporizer cells spawning in the map.
+float autocvar_g_random_items_vaporizer_cells_probability;
+/// \brief Probability of random invisibility spawning in the map.
+float autocvar_g_random_items_invisibility_probability;
+/// \brief Probability of random extra life spawning in the map.
+float autocvar_g_random_items_extralife_probability;
+/// \brief Probability of random speed spawning in the map.
+float autocvar_g_random_items_speed_probability;
+
+// Loot
+
+bool autocvar_g_random_loot; ///< Whether to enable random loot.
+
+float autocvar_g_random_loot_min; ///< Minimum amount of loot items.
+float autocvar_g_random_loot_max; ///< Maximum amount of loot items.
+float autocvar_g_random_loot_time; ///< Amount of time the loot will stay.
+float autocvar_g_random_loot_spread; ///< How far can loot be thrown.
+
+// Loot probability cvars
+
+/// \brief Probability of random health items spawning as loot.
+float autocvar_g_random_loot_health_probability;
+/// \brief Probability of random armor items spawning as loot.
+float autocvar_g_random_loot_armor_probability;
+/// \brief Probability of random resource items spawning as loot.
+float autocvar_g_random_loot_resource_probability;
+/// \brief Probability of random weapons spawning as loot.
+float autocvar_g_random_loot_weapon_probability;
+/// \brief Probability of random powerups spawning as loot.
+float autocvar_g_random_loot_powerup_probability;
+
+/// \brief Probability of random small health spawning as loot.
+float autocvar_g_random_loot_health_small_probability;
+/// \brief Probability of random medium health spawning as loot.
+float autocvar_g_random_loot_health_medium_probability;
+/// \brief Probability of random big health spawning as loot.
+float autocvar_g_random_loot_health_big_probability;
+/// \brief Probability of random mega health spawning as loot.
+float autocvar_g_random_loot_health_mega_probability;
+
+/// \brief Probability of random small armor spawning as loot.
+float autocvar_g_random_loot_armor_small_probability;
+/// \brief Probability of random medium armor.spawning as loot.
+float autocvar_g_random_loot_armor_medium_probability;
+/// \brief Probability of random big armor spawning as loot.
+float autocvar_g_random_loot_armor_big_probability;
+/// \brief Probability of random mega armor spawning as loot.
+float autocvar_g_random_loot_armor_mega_probability;
+
+/// \brief Probability of random shells spawning as loot.
+float autocvar_g_random_loot_resource_shells_probability;
+/// \brief Probability of random bullets spawning as loot.
+float autocvar_g_random_loot_resource_bullets_probability;
+/// \brief Probability of random rockets spawning as loot.
+float autocvar_g_random_loot_resource_rockets_probability;
+/// \brief Probability of random cells spawning as loot.
+float autocvar_g_random_loot_resource_cells_probability;
+/// \brief Probability of random plasma spawning as loot.
+float autocvar_g_random_loot_resource_plasma_probability;
+/// \brief Probability of random fuel spawning as loot.
+float autocvar_g_random_loot_resource_fuel_probability;
+
+/// \brief Probability of random blaster spawning as loot.
+float autocvar_g_random_loot_weapon_blaster_probability;
+/// \brief Probability of random shotgun spawning as loot.
+float autocvar_g_random_loot_weapon_shotgun_probability;
+/// \brief Probability of random machinegun spawning as loot.
+float autocvar_g_random_loot_weapon_machinegun_probability;
+/// \brief Probability of random mortar spawning as loot.
+float autocvar_g_random_loot_weapon_mortar_probability;
+/// \brief Probability of random electro spawning as loot.
+float autocvar_g_random_loot_weapon_electro_probability;
+/// \brief Probability of random crylink spawning as loot.
+float autocvar_g_random_loot_weapon_crylink_probability;
+/// \brief Probability of random vortex spawning as loot.
+float autocvar_g_random_loot_weapon_vortex_probability;
+/// \brief Probability of random hagar spawning as loot.
+float autocvar_g_random_loot_weapon_hagar_probability;
+/// \brief Probability of random devastator spawning as loot.
+float autocvar_g_random_loot_weapon_devastator_probability;
+/// \brief Probability of random shockwave spawning as loot.
+float autocvar_g_random_loot_weapon_shockwave_probability;
+/// \brief Probability of random arc spawning as loot.
+float autocvar_g_random_loot_weapon_arc_probability;
+/// \brief Probability of random hook spawning as loot.
+float autocvar_g_random_loot_weapon_hook_probability;
+/// \brief Probability of random tuba spawning as loot.
+float autocvar_g_random_loot_weapon_tuba_probability;
+/// \brief Probability of random port-o-launch spawning as loot.
+float autocvar_g_random_loot_weapon_porto_probability;
+/// \brief Probability of random fireball spawning as loot.
+float autocvar_g_random_loot_weapon_fireball_probability;
+/// \brief Probability of random mine layer spawning as loot.
+float autocvar_g_random_loot_weapon_minelayer_probability;
+/// \brief Probability of random HLAC spawning as loot.
+float autocvar_g_random_loot_weapon_hlac_probability;
+/// \brief Probability of random rifle spawning as loot.
+float autocvar_g_random_loot_weapon_rifle_probability;
+/// \brief Probability of random TAG seeker spawning as loot.
+float autocvar_g_random_loot_weapon_seeker_probability;
+/// \brief Probability of random vaporizer spawning as loot.
+float autocvar_g_random_loot_weapon_vaporizer_probability;
+
+/// \brief Probability of random strength spawning as loot.
+float autocvar_g_random_loot_strength_probability;
+/// \brief Probability of random shield spawning as loot.
+float autocvar_g_random_loot_shield_probability;
+/// \brief Probability of random fuel regeneration spawning as loot.
+float autocvar_g_random_loot_fuel_regen_probability;
+/// \brief Probability of random jetpack spawning as loot.
+float autocvar_g_random_loot_jetpack_probability;
+
+/// \brief Probability of random vaporizer cells spawning as loot.
+float autocvar_g_random_loot_vaporizer_cells_probability;
+/// \brief Probability of random invisibility spawning as loot.
+float autocvar_g_random_loot_invisibility_probability;
+/// \brief Probability of random extra life spawning as loot.
+float autocvar_g_random_loot_extralife_probability;
+/// \brief Probability of random speed spawning as loot.
+float autocvar_g_random_loot_speed_probability;
+
+/// \brief Holds whether random item is spawning. Used to prevent infinite
+/// recursion.
+bool random_items_is_spawning = false;
+
+//========================= Free functions ====================================
+
+/// \brief Returns list of classnames to replace a map item with.
+/// \param[in] item Item to inspect.
+/// \return List of classnames to replace a map item with.
+string RandomItems_GetItemReplacementClassNames(entity item)
+{
+       switch (item.classname)
+       {
+               case "item_health_small":
+               {
+                       return autocvar_g_random_items_replace_health_small;
+               }
+               case "item_health_medium":
+               {
+                       return autocvar_g_random_items_replace_health_medium;
+               }
+               case "item_health_big":
+               case "item_health_large":
+               {
+                       return autocvar_g_random_items_replace_health_big;
+               }
+               case "item_health_mega":
+               {
+                       return autocvar_g_random_items_replace_health_mega;
+               }
+               case "item_armor_small":
+               {
+                       return autocvar_g_random_items_replace_armor_small;
+               }
+               case "item_armor_medium":
+               {
+                       return autocvar_g_random_items_replace_armor_medium;
+               }
+               case "item_armor_big":
+               case "item_armor_large":
+               {
+                       return autocvar_g_random_items_replace_armor_big;
+               }
+               case "item_armor_mega":
+               {
+                       return autocvar_g_random_items_replace_armor_mega;
+               }
+               case "item_shells":
+               {
+                       return autocvar_g_random_items_replace_item_shells;
+               }
+               case "item_bullets":
+               {
+                       return autocvar_g_random_items_replace_item_bullets;
+               }
+               case "item_rockets":
+               {
+                       return autocvar_g_random_items_replace_item_rockets;
+               }
+               case "item_cells":
+               {
+                       return autocvar_g_random_items_replace_item_cells;
+               }
+               case "item_plasma":
+               {
+                       return autocvar_g_random_items_replace_item_plasma;
+               }
+               case "item_fuel":
+               {
+                       return autocvar_g_random_items_replace_item_fuel;
+               }
+               case "weapon_blaster":
+               case "weapon_laser":
+               {
+                       return autocvar_g_random_items_replace_weapon_blaster;
+               }
+               case "weapon_shotgun":
+               {
+                       return autocvar_g_random_items_replace_weapon_shotgun;
+               }
+               case "weapon_machinegun":
+               case "weapon_uzi":
+               {
+                       return autocvar_g_random_items_replace_weapon_machinegun;
+               }
+               case "weapon_mortar":
+               case "weapon_grenadelauncher":
+               {
+                       return autocvar_g_random_items_replace_weapon_mortar;
+               }
+               case "weapon_electro":
+               {
+                       return autocvar_g_random_items_replace_weapon_electro;
+               }
+               case "weapon_crylink":
+               {
+                       return autocvar_g_random_items_replace_weapon_crylink;
+               }
+               case "weapon_vortex":
+               case "weapon_nex":
+               {
+                       return autocvar_g_random_items_replace_weapon_vortex;
+               }
+               case "weapon_hagar":
+               {
+                       return autocvar_g_random_items_replace_weapon_hagar;
+               }
+               case "weapon_devastator":
+               case "weapon_rocketlauncher":
+               {
+                       return autocvar_g_random_items_replace_weapon_devastator;
+               }
+               case "weapon_shockwave":
+               {
+                       return autocvar_g_random_items_replace_weapon_shockwave;
+               }
+               case "weapon_arc":
+               {
+                       return autocvar_g_random_items_replace_weapon_arc;
+               }
+               case "weapon_hook":
+               {
+                       return autocvar_g_random_items_replace_weapon_hook;
+               }
+               case "weapon_tuba":
+               {
+                       return autocvar_g_random_items_replace_weapon_tuba;
+               }
+               case "weapon_porto":
+               {
+                       return autocvar_g_random_items_replace_weapon_porto;
+               }
+               case "weapon_fireball":
+               {
+                       return autocvar_g_random_items_replace_weapon_fireball;
+               }
+               case "weapon_minelayer":
+               {
+                       return autocvar_g_random_items_replace_weapon_minelayer;
+               }
+               case "weapon_hlac":
+               {
+                       return autocvar_g_random_items_replace_weapon_hlac;
+               }
+               case "weapon_rifle":
+               case "weapon_campingrifle":
+               case "weapon_sniperrifle":
+               {
+                       return autocvar_g_random_items_replace_weapon_rifle;
+               }
+               case "weapon_seeker":
+               {
+                       return autocvar_g_random_items_replace_weapon_seeker;
+               }
+               case "weapon_vaporizer":
+               case "weapon_minstanex":
+               {
+                       return autocvar_g_random_items_replace_weapon_vaporizer;
+               }
+               case "item_strength":
+               {
+                       return autocvar_g_random_items_replace_item_strength;
+               }
+               case "item_invincible":
+               {
+                       return autocvar_g_random_items_replace_item_shield;
+               }
+               case "item_fuel_regen":
+               {
+                       return autocvar_g_random_items_replace_item_fuel_regen;
+               }
+               case "item_jetpack":
+               {
+                       return autocvar_g_random_items_replace_item_jetpack;
+               }
+               case "item_vaporizer_cells":
+               {
+                       return autocvar_g_random_items_replace_item_vaporizer_cells;
+               }
+               case "item_invisibility":
+               {
+                       return autocvar_g_random_items_replace_item_invisibility;
+               }
+               case "item_extralife":
+               {
+                       return autocvar_g_random_items_replace_item_extralife;
+               }
+               case "item_speed":
+               {
+                       return autocvar_g_random_items_replace_item_speed;
+               }
+               case "replacedweapon":
+               {
+                       switch (item.weapon)
+                       {
+                               case WEP_MINE_LAYER.m_id:
+                               {
+                                       return autocvar_g_random_items_replace_weapon_minelayer;
+                               }
+                               case WEP_HLAC.m_id:
+                               {
+                                       return autocvar_g_random_items_replace_weapon_hlac;
+                               }
+                               case WEP_RIFLE.m_id:
+                               {
+                                       return autocvar_g_random_items_replace_weapon_rifle;
+                               }
+                               case WEP_SEEKER.m_id:
+                               {
+                                       return autocvar_g_random_items_replace_weapon_seeker;
+                               }
+                               default:
+                               {
+                                       return "";
+                               }
+                       }
+               }
+               default:
+               {
+                       return "";
+               }
+       }
+}
+
+/// \brief Returns a random instagib classname of the map item.
+/// \return Random instagib classname of the map item.
+string RandomItems_GetRandomInstagibMapItemClassName()
+{
+       RandomSelection_Init();
+       RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_INSTAGIB_VAPORIZER_CELLS,
+               autocvar_g_random_items_vaporizer_cells_probability, 1);
+       RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_INSTAGIB_INVISIBILITY,
+               autocvar_g_random_items_invisibility_probability, 1);
+       RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_INSTAGIB_EXTRA_LIFE,
+               autocvar_g_random_items_extralife_probability, 1);
+       RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_INSTAGIB_SPEED,
+               autocvar_g_random_items_speed_probability, 1);
+       int item_type = RandomSelection_chosen_float;
+       switch (item_type)
+       {
+               case RANDOM_ITEM_SUBTYPE_INSTAGIB_VAPORIZER_CELLS:
+               {
+                       return "item_vaporizer_cells";
+               }
+               case RANDOM_ITEM_SUBTYPE_INSTAGIB_INVISIBILITY:
+               {
+                       return "item_invisibility";
+               }
+               case RANDOM_ITEM_SUBTYPE_INSTAGIB_EXTRA_LIFE:
+               {
+                       return "item_extralife";
+               }
+               case RANDOM_ITEM_SUBTYPE_INSTAGIB_SPEED:
+               {
+                       return "item_speed";
+               }
+       }
+       return "";
+}
+
+/// \brief Returns a random classname of the map item.
+/// \return Random classname of the map item.
+string RandomItems_GetRandomMapItemClassName()
+{
+       if (autocvar_g_instagib)
+       {
+               return RandomItems_GetRandomInstagibMapItemClassName();
+       }
+       RandomSelection_Init();
+       RandomSelection_AddFloat(RANDOM_ITEM_TYPE_HEALTH,
+               autocvar_g_random_items_health_probability, 1);
+       RandomSelection_AddFloat(RANDOM_ITEM_TYPE_ARMOR,
+               autocvar_g_random_items_armor_probability, 1);
+       RandomSelection_AddFloat(RANDOM_ITEM_TYPE_RESOURCE,
+               autocvar_g_random_items_resource_probability, 1);
+       RandomSelection_AddFloat(RANDOM_ITEM_TYPE_WEAPON,
+               autocvar_g_random_items_weapon_probability, 1);
+       RandomSelection_AddFloat(RANDOM_ITEM_TYPE_POWERUP,
+               autocvar_g_random_items_powerup_probability, 1);
+       int item_type = RandomSelection_chosen_float;
+       switch (item_type)
+       {
+               case RANDOM_ITEM_TYPE_HEALTH:
+               {
+                       RandomSelection_Init();
+                       RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_HEALTH_SMALL,
+                               autocvar_g_random_items_health_small_probability, 1);
+                       RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_HEALTH_MEDIUM,
+                               autocvar_g_random_items_health_medium_probability, 1);
+                       RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_HEALTH_BIG,
+                               autocvar_g_random_items_health_big_probability, 1);
+                       RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_HEALTH_MEGA,
+                               autocvar_g_random_items_health_mega_probability, 1);
+                       item_type = RandomSelection_chosen_float;
+                       switch (item_type)
+                       {
+                               case RANDOM_ITEM_SUBTYPE_HEALTH_SMALL:
+                               {
+                                       return "item_health_small";
+                               }
+                               case RANDOM_ITEM_SUBTYPE_HEALTH_MEDIUM:
+                               {
+                                       return "item_health_medium";
+                               }
+                               case RANDOM_ITEM_SUBTYPE_HEALTH_BIG:
+                               {
+                                       return "item_health_big";
+                               }
+                               case RANDOM_ITEM_SUBTYPE_HEALTH_MEGA:
+                               {
+                                       return "item_health_mega";
+                               }
+                       }
+                       return "";
+               }
+               case RANDOM_ITEM_TYPE_ARMOR:
+               {
+                       RandomSelection_Init();
+                       RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_ARMOR_SMALL,
+                               autocvar_g_random_items_armor_small_probability, 1);
+                       RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_ARMOR_MEDIUM,
+                               autocvar_g_random_items_armor_medium_probability, 1);
+                       RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_ARMOR_BIG,
+                               autocvar_g_random_items_armor_big_probability, 1);
+                       RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_ARMOR_MEGA,
+                               autocvar_g_random_items_armor_mega_probability, 1);
+                       item_type = RandomSelection_chosen_float;
+                       switch (item_type)
+                       {
+                               case RANDOM_ITEM_SUBTYPE_ARMOR_SMALL:
+                               {
+                                       return "item_armor_small";
+                               }
+                               case RANDOM_ITEM_SUBTYPE_ARMOR_MEDIUM:
+                               {
+                                       return "item_armor_medium";
+                               }
+                               case RANDOM_ITEM_SUBTYPE_ARMOR_BIG:
+                               {
+                                       return "item_armor_big";
+                               }
+                               case RANDOM_ITEM_SUBTYPE_ARMOR_MEGA:
+                               {
+                                       return "item_armor_mega";
+                               }
+                       }
+                       return "";
+               }
+               case RANDOM_ITEM_TYPE_RESOURCE:
+               {
+                       RandomSelection_Init();
+                       RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_RESOURCE_SHELLS,
+                               autocvar_g_random_items_resource_shells_probability, 1);
+                       RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_RESOURCE_BULLETS,
+                               autocvar_g_random_items_resource_bullets_probability, 1);
+                       RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_RESOURCE_ROCKETS,
+                               autocvar_g_random_items_resource_rockets_probability, 1);
+                       RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_RESOURCE_CELLS,
+                               autocvar_g_random_items_resource_cells_probability, 1);
+                       RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_RESOURCE_PLASMA,
+                               autocvar_g_random_items_resource_plasma_probability, 1);
+                       RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_RESOURCE_FUEL,
+                               autocvar_g_random_items_resource_fuel_probability, 1);
+                       item_type = RandomSelection_chosen_float;
+                       switch (item_type)
+                       {
+                               case RANDOM_ITEM_SUBTYPE_RESOURCE_SHELLS:
+                               {
+                                       return "item_shells";
+                               }
+                               case RANDOM_ITEM_SUBTYPE_RESOURCE_BULLETS:
+                               {
+                                       return "item_bullets";
+                               }
+                               case RANDOM_ITEM_SUBTYPE_RESOURCE_ROCKETS:
+                               {
+                                       return "item_rockets";
+                               }
+                               case RANDOM_ITEM_SUBTYPE_RESOURCE_CELLS:
+                               {
+                                       return "item_cells";
+                               }
+                               case RANDOM_ITEM_SUBTYPE_RESOURCE_PLASMA:
+                               {
+                                       return "item_plasma";
+                               }
+                               case RANDOM_ITEM_SUBTYPE_RESOURCE_FUEL:
+                               {
+                                       return "item_fuel";
+                               }
+                       }
+                       return "";
+               }
+               case RANDOM_ITEM_TYPE_WEAPON:
+               {
+                       RandomSelection_Init();
+                       RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_WEAPON_BLASTER,
+                               autocvar_g_random_items_weapon_blaster_probability, 1);
+                       RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_WEAPON_SHOTGUN,
+                               autocvar_g_random_items_weapon_shotgun_probability, 1);
+                       RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_WEAPON_MACHINEGUN,
+                               autocvar_g_random_items_weapon_machinegun_probability, 1);
+                       RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_WEAPON_MORTAR,
+                               autocvar_g_random_items_weapon_mortar_probability, 1);
+                       RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_WEAPON_ELECTRO,
+                               autocvar_g_random_items_weapon_electro_probability, 1);
+                       RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_WEAPON_CRYLINK,
+                               autocvar_g_random_items_weapon_crylink_probability, 1);
+                       RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_WEAPON_VORTEX,
+                               autocvar_g_random_items_weapon_vortex_probability, 1);
+                       RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_WEAPON_HAGAR,
+                               autocvar_g_random_items_weapon_hagar_probability, 1);
+                       RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_WEAPON_DEVASTATOR,
+                               autocvar_g_random_items_weapon_devastator_probability, 1);
+                       RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_WEAPON_SHOCKWAVE,
+                               autocvar_g_random_items_weapon_shockwave_probability, 1);
+                       RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_WEAPON_ARC,
+                               autocvar_g_random_items_weapon_arc_probability, 1);
+                       RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_WEAPON_HOOK,
+                               autocvar_g_random_items_weapon_hook_probability, 1);
+                       RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_WEAPON_TUBA,
+                               autocvar_g_random_items_weapon_tuba_probability, 1);
+                       RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_WEAPON_PORTO,
+                               autocvar_g_random_items_weapon_porto_probability, 1);
+                       RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_WEAPON_FIREBALL,
+                               autocvar_g_random_items_weapon_fireball_probability, 1);
+                       RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_WEAPON_MINELAYER,
+                               autocvar_g_random_items_weapon_minelayer_probability, 1);
+                       RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_WEAPON_HLAC,
+                               autocvar_g_random_items_weapon_hlac_probability, 1);
+                       RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_WEAPON_RIFLE,
+                               autocvar_g_random_items_weapon_rifle_probability, 1);
+                       RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_WEAPON_SEEKER,
+                               autocvar_g_random_items_weapon_seeker_probability, 1);
+                       RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_WEAPON_VAPORIZER,
+                               autocvar_g_random_items_weapon_vaporizer_probability, 1);
+                       item_type = RandomSelection_chosen_float;
+                       switch (item_type)
+                       {
+                               case RANDOM_ITEM_SUBTYPE_WEAPON_BLASTER:
+                               {
+                                       return "weapon_blaster";
+                               }
+                               case RANDOM_ITEM_SUBTYPE_WEAPON_SHOTGUN:
+                               {
+                                       return "weapon_shotgun";
+                               }
+                               case RANDOM_ITEM_SUBTYPE_WEAPON_MACHINEGUN:
+                               {
+                                       return "weapon_machinegun";
+                               }
+                               case RANDOM_ITEM_SUBTYPE_WEAPON_MORTAR:
+                               {
+                                       return "weapon_mortar";
+                               }
+                               case RANDOM_ITEM_SUBTYPE_WEAPON_ELECTRO:
+                               {
+                                       return "weapon_electro";
+                               }
+                               case RANDOM_ITEM_SUBTYPE_WEAPON_CRYLINK:
+                               {
+                                       return "weapon_crylink";
+                               }
+                               case RANDOM_ITEM_SUBTYPE_WEAPON_VORTEX:
+                               {
+                                       return "weapon_vortex";
+                               }
+                               case RANDOM_ITEM_SUBTYPE_WEAPON_HAGAR:
+                               {
+                                       return "weapon_hagar";
+                               }
+                               case RANDOM_ITEM_SUBTYPE_WEAPON_DEVASTATOR:
+                               {
+                                       return "weapon_devastator";
+                               }
+                               case RANDOM_ITEM_SUBTYPE_WEAPON_SHOCKWAVE:
+                               {
+                                       return "weapon_shockwave";
+                               }
+                               case RANDOM_ITEM_SUBTYPE_WEAPON_ARC:
+                               {
+                                       return "weapon_arc";
+                               }
+                               case RANDOM_ITEM_SUBTYPE_WEAPON_HOOK:
+                               {
+                                       return "weapon_hook";
+                               }
+                               case RANDOM_ITEM_SUBTYPE_WEAPON_TUBA:
+                               {
+                                       return "weapon_tuba";
+                               }
+                               case RANDOM_ITEM_SUBTYPE_WEAPON_PORTO:
+                               {
+                                       return "weapon_porto";
+                               }
+                               case RANDOM_ITEM_SUBTYPE_WEAPON_FIREBALL:
+                               {
+                                       return "weapon_fireball";
+                               }
+                               case RANDOM_ITEM_SUBTYPE_WEAPON_MINELAYER:
+                               {
+                                       return "weapon_minelayer";
+                               }
+                               case RANDOM_ITEM_SUBTYPE_WEAPON_HLAC:
+                               {
+                                       return "weapon_hlac";
+                               }
+                               case RANDOM_ITEM_SUBTYPE_WEAPON_RIFLE:
+                               {
+                                       return "weapon_rifle";
+                               }
+                               case RANDOM_ITEM_SUBTYPE_WEAPON_SEEKER:
+                               {
+                                       return "weapon_seeker";
+                               }
+                               case RANDOM_ITEM_SUBTYPE_WEAPON_VAPORIZER:
+                               {
+                                       return "weapon_vaporizer";
+                               }
+                       }
+                       return "";
+               }
+               case RANDOM_ITEM_TYPE_POWERUP:
+               {
+                       RandomSelection_Init();
+                       RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_POWERUP_STRENGTH,
+                               autocvar_g_random_items_strength_probability, 1);
+                       RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_POWERUP_SHIELD,
+                               autocvar_g_random_items_shield_probability, 1);
+                       RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_POWERUP_FUEL_REGEN,
+                               autocvar_g_random_items_fuel_regen_probability, 1);
+                       RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_POWERUP_JETPACK,
+                               autocvar_g_random_items_jetpack_probability, 1);
+                       item_type = RandomSelection_chosen_float;
+                       switch (item_type)
+                       {
+                               case RANDOM_ITEM_SUBTYPE_POWERUP_STRENGTH:
+                               {
+                                       return "item_strength";
+                               }
+                               case RANDOM_ITEM_SUBTYPE_POWERUP_SHIELD:
+                               {
+                                       return "item_invincible";
+                               }
+                               case RANDOM_ITEM_SUBTYPE_POWERUP_FUEL_REGEN:
+                               {
+                                       return "item_fuel_regen";
+                               }
+                               case RANDOM_ITEM_SUBTYPE_POWERUP_JETPACK:
+                               {
+                                       return "item_jetpack";
+                               }
+                       }
+                       return "";
+               }
+       }
+       return "";
+}
+
+/// \brief Replaces a map item.
+/// \param[in] item Item to replace.
+/// \return Spawned item on success, NULL otherwise.
+entity RandomItems_ReplaceMapItem(entity item)
+{
+       //PrintToChatAll(strcat("Replacing ", item.classname));
+       string new_classnames = RandomItems_GetItemReplacementClassNames(item);
+       if (new_classnames == "")
+       {
+               return NULL;
+       }
+       string new_classname;
+       if (new_classnames == "random")
+       {
+               new_classname = RandomItems_GetRandomMapItemClassName();
+               if (new_classname == "")
+               {
+                       return NULL;
+               }
+       }
+       else
+       {
+               int num_new_classnames = tokenize_console(new_classnames);
+               if (num_new_classnames == 1)
+               {
+                       new_classname = new_classnames;
+               }
+               else
+               {
+                       int classname_index = floor(random() * num_new_classnames);
+                       new_classname = argv(classname_index);
+               }
+       }
+       //PrintToChatAll(strcat("Replacing with ", new_classname));
+       if (new_classname == item.classname)
+       {
+               return NULL;
+       }
+       random_items_is_spawning = true;
+       entity new_item = Item_Create(strzone(new_classname), item.origin);
+       random_items_is_spawning = false;
+       return new_item;
+}
+
+/// \brief Returns a random instagib classname of the loot item.
+/// \return Random instagib classname of the loot item.
+string RandomItems_GetRandomInstagibLootItemClassName()
+{
+       RandomSelection_Init();
+       RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_INSTAGIB_VAPORIZER_CELLS,
+               autocvar_g_random_loot_vaporizer_cells_probability, 1);
+       RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_INSTAGIB_INVISIBILITY,
+               autocvar_g_random_loot_invisibility_probability, 1);
+       RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_INSTAGIB_EXTRA_LIFE,
+               autocvar_g_random_loot_extralife_probability, 1);
+       RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_INSTAGIB_SPEED,
+               autocvar_g_random_loot_speed_probability, 1);
+       int item_type = RandomSelection_chosen_float;
+       switch (item_type)
+       {
+               case RANDOM_ITEM_SUBTYPE_INSTAGIB_VAPORIZER_CELLS:
+               {
+                       return "item_vaporizer_cells";
+               }
+               case RANDOM_ITEM_SUBTYPE_INSTAGIB_INVISIBILITY:
+               {
+                       return "item_invisibility";
+               }
+               case RANDOM_ITEM_SUBTYPE_INSTAGIB_EXTRA_LIFE:
+               {
+                       return "item_extralife";
+               }
+               case RANDOM_ITEM_SUBTYPE_INSTAGIB_SPEED:
+               {
+                       return "item_speed";
+               }
+       }
+       return "";
+}
+
+
+/// \brief Returns a random classname of the loot item.
+/// \return Random classname of the loot item.
+string RandomItems_GetRandomLootItemClassName()
+{
+       if (autocvar_g_instagib)
+       {
+               return RandomItems_GetRandomInstagibLootItemClassName();
+       }
+       RandomSelection_Init();
+       RandomSelection_AddFloat(RANDOM_ITEM_TYPE_HEALTH,
+               autocvar_g_random_loot_health_probability, 1);
+       RandomSelection_AddFloat(RANDOM_ITEM_TYPE_ARMOR,
+               autocvar_g_random_loot_armor_probability, 1);
+       RandomSelection_AddFloat(RANDOM_ITEM_TYPE_RESOURCE,
+               autocvar_g_random_loot_resource_probability, 1);
+       RandomSelection_AddFloat(RANDOM_ITEM_TYPE_WEAPON,
+               autocvar_g_random_loot_weapon_probability, 1);
+       RandomSelection_AddFloat(RANDOM_ITEM_TYPE_POWERUP,
+               autocvar_g_random_loot_powerup_probability, 1);
+       int item_type = RandomSelection_chosen_float;
+       switch (item_type)
+       {
+               case RANDOM_ITEM_TYPE_HEALTH:
+               {
+                       RandomSelection_Init();
+                       RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_HEALTH_SMALL,
+                               autocvar_g_random_loot_health_small_probability, 1);
+                       RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_HEALTH_MEDIUM,
+                               autocvar_g_random_loot_health_medium_probability, 1);
+                       RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_HEALTH_BIG,
+                               autocvar_g_random_loot_health_big_probability, 1);
+                       RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_HEALTH_MEGA,
+                               autocvar_g_random_loot_health_mega_probability, 1);
+                       item_type = RandomSelection_chosen_float;
+                       switch (item_type)
+                       {
+                               case RANDOM_ITEM_SUBTYPE_HEALTH_SMALL:
+                               {
+                                       return "item_health_small";
+                               }
+                               case RANDOM_ITEM_SUBTYPE_HEALTH_MEDIUM:
+                               {
+                                       return "item_health_medium";
+                               }
+                               case RANDOM_ITEM_SUBTYPE_HEALTH_BIG:
+                               {
+                                       return "item_health_big";
+                               }
+                               case RANDOM_ITEM_SUBTYPE_HEALTH_MEGA:
+                               {
+                                       return "item_health_mega";
+                               }
+                       }
+                       return "";
+               }
+               case RANDOM_ITEM_TYPE_ARMOR:
+               {
+                       RandomSelection_Init();
+                       RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_ARMOR_SMALL,
+                               autocvar_g_random_loot_armor_small_probability, 1);
+                       RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_ARMOR_MEDIUM,
+                               autocvar_g_random_loot_armor_medium_probability, 1);
+                       RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_ARMOR_BIG,
+                               autocvar_g_random_loot_armor_big_probability, 1);
+                       RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_ARMOR_MEGA,
+                               autocvar_g_random_loot_armor_mega_probability, 1);
+                       item_type = RandomSelection_chosen_float;
+                       switch (item_type)
+                       {
+                               case RANDOM_ITEM_SUBTYPE_ARMOR_SMALL:
+                               {
+                                       return "item_armor_small";
+                               }
+                               case RANDOM_ITEM_SUBTYPE_ARMOR_MEDIUM:
+                               {
+                                       return "item_armor_medium";
+                               }
+                               case RANDOM_ITEM_SUBTYPE_ARMOR_BIG:
+                               {
+                                       return "item_armor_big";
+                               }
+                               case RANDOM_ITEM_SUBTYPE_ARMOR_MEGA:
+                               {
+                                       return "item_armor_mega";
+                               }
+                       }
+                       return "";
+               }
+               case RANDOM_ITEM_TYPE_RESOURCE:
+               {
+                       RandomSelection_Init();
+                       RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_RESOURCE_SHELLS,
+                               autocvar_g_random_loot_resource_shells_probability, 1);
+                       RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_RESOURCE_BULLETS,
+                               autocvar_g_random_loot_resource_bullets_probability, 1);
+                       RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_RESOURCE_ROCKETS,
+                               autocvar_g_random_loot_resource_rockets_probability, 1);
+                       RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_RESOURCE_CELLS,
+                               autocvar_g_random_loot_resource_cells_probability, 1);
+                       RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_RESOURCE_PLASMA,
+                               autocvar_g_random_loot_resource_plasma_probability, 1);
+                       RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_RESOURCE_FUEL,
+                               autocvar_g_random_loot_resource_fuel_probability, 1);
+                       item_type = RandomSelection_chosen_float;
+                       switch (item_type)
+                       {
+                               case RANDOM_ITEM_SUBTYPE_RESOURCE_SHELLS:
+                               {
+                                       return "item_shells";
+                               }
+                               case RANDOM_ITEM_SUBTYPE_RESOURCE_BULLETS:
+                               {
+                                       return "item_bullets";
+                               }
+                               case RANDOM_ITEM_SUBTYPE_RESOURCE_ROCKETS:
+                               {
+                                       return "item_rockets";
+                               }
+                               case RANDOM_ITEM_SUBTYPE_RESOURCE_CELLS:
+                               {
+                                       return "item_cells";
+                               }
+                               case RANDOM_ITEM_SUBTYPE_RESOURCE_PLASMA:
+                               {
+                                       return "item_plasma";
+                               }
+                               case RANDOM_ITEM_SUBTYPE_RESOURCE_FUEL:
+                               {
+                                       return "item_fuel";
+                               }
+                       }
+                       return "";
+               }
+               case RANDOM_ITEM_TYPE_WEAPON:
+               {
+                       RandomSelection_Init();
+                       RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_WEAPON_BLASTER,
+                               autocvar_g_random_loot_weapon_blaster_probability, 1);
+                       RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_WEAPON_SHOTGUN,
+                               autocvar_g_random_loot_weapon_shotgun_probability, 1);
+                       RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_WEAPON_MACHINEGUN,
+                               autocvar_g_random_loot_weapon_machinegun_probability, 1);
+                       RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_WEAPON_MORTAR,
+                               autocvar_g_random_loot_weapon_mortar_probability, 1);
+                       RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_WEAPON_ELECTRO,
+                               autocvar_g_random_loot_weapon_electro_probability, 1);
+                       RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_WEAPON_CRYLINK,
+                               autocvar_g_random_loot_weapon_crylink_probability, 1);
+                       RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_WEAPON_VORTEX,
+                               autocvar_g_random_loot_weapon_vortex_probability, 1);
+                       RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_WEAPON_HAGAR,
+                               autocvar_g_random_loot_weapon_hagar_probability, 1);
+                       RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_WEAPON_DEVASTATOR,
+                               autocvar_g_random_loot_weapon_devastator_probability, 1);
+                       RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_WEAPON_SHOCKWAVE,
+                               autocvar_g_random_loot_weapon_shockwave_probability, 1);
+                       RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_WEAPON_ARC,
+                               autocvar_g_random_loot_weapon_arc_probability, 1);
+                       RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_WEAPON_HOOK,
+                               autocvar_g_random_loot_weapon_hook_probability, 1);
+                       RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_WEAPON_TUBA,
+                               autocvar_g_random_loot_weapon_tuba_probability, 1);
+                       RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_WEAPON_PORTO,
+                               autocvar_g_random_loot_weapon_porto_probability, 1);
+                       RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_WEAPON_FIREBALL,
+                               autocvar_g_random_loot_weapon_fireball_probability, 1);
+                       RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_WEAPON_MINELAYER,
+                               autocvar_g_random_loot_weapon_minelayer_probability, 1);
+                       RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_WEAPON_HLAC,
+                               autocvar_g_random_loot_weapon_hlac_probability, 1);
+                       RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_WEAPON_RIFLE,
+                               autocvar_g_random_loot_weapon_rifle_probability, 1);
+                       RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_WEAPON_SEEKER,
+                               autocvar_g_random_loot_weapon_seeker_probability, 1);
+                       RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_WEAPON_VAPORIZER,
+                               autocvar_g_random_loot_weapon_vaporizer_probability, 1);
+                       item_type = RandomSelection_chosen_float;
+                       switch (item_type)
+                       {
+                               case RANDOM_ITEM_SUBTYPE_WEAPON_BLASTER:
+                               {
+                                       return "weapon_blaster";
+                               }
+                               case RANDOM_ITEM_SUBTYPE_WEAPON_SHOTGUN:
+                               {
+                                       return "weapon_shotgun";
+                               }
+                               case RANDOM_ITEM_SUBTYPE_WEAPON_MACHINEGUN:
+                               {
+                                       return "weapon_machinegun";
+                               }
+                               case RANDOM_ITEM_SUBTYPE_WEAPON_MORTAR:
+                               {
+                                       return "weapon_mortar";
+                               }
+                               case RANDOM_ITEM_SUBTYPE_WEAPON_ELECTRO:
+                               {
+                                       return "weapon_electro";
+                               }
+                               case RANDOM_ITEM_SUBTYPE_WEAPON_CRYLINK:
+                               {
+                                       return "weapon_crylink";
+                               }
+                               case RANDOM_ITEM_SUBTYPE_WEAPON_VORTEX:
+                               {
+                                       return "weapon_vortex";
+                               }
+                               case RANDOM_ITEM_SUBTYPE_WEAPON_HAGAR:
+                               {
+                                       return "weapon_hagar";
+                               }
+                               case RANDOM_ITEM_SUBTYPE_WEAPON_DEVASTATOR:
+                               {
+                                       return "weapon_devastator";
+                               }
+                               case RANDOM_ITEM_SUBTYPE_WEAPON_SHOCKWAVE:
+                               {
+                                       return "weapon_shockwave";
+                               }
+                               case RANDOM_ITEM_SUBTYPE_WEAPON_ARC:
+                               {
+                                       return "weapon_arc";
+                               }
+                               case RANDOM_ITEM_SUBTYPE_WEAPON_HOOK:
+                               {
+                                       return "weapon_hook";
+                               }
+                               case RANDOM_ITEM_SUBTYPE_WEAPON_TUBA:
+                               {
+                                       return "weapon_tuba";
+                               }
+                               case RANDOM_ITEM_SUBTYPE_WEAPON_PORTO:
+                               {
+                                       return "weapon_porto";
+                               }
+                               case RANDOM_ITEM_SUBTYPE_WEAPON_FIREBALL:
+                               {
+                                       return "weapon_fireball";
+                               }
+                               case RANDOM_ITEM_SUBTYPE_WEAPON_MINELAYER:
+                               {
+                                       return "weapon_minelayer";
+                               }
+                               case RANDOM_ITEM_SUBTYPE_WEAPON_HLAC:
+                               {
+                                       return "weapon_hlac";
+                               }
+                               case RANDOM_ITEM_SUBTYPE_WEAPON_RIFLE:
+                               {
+                                       return "weapon_rifle";
+                               }
+                               case RANDOM_ITEM_SUBTYPE_WEAPON_SEEKER:
+                               {
+                                       return "weapon_seeker";
+                               }
+                               case RANDOM_ITEM_SUBTYPE_WEAPON_VAPORIZER:
+                               {
+                                       return "weapon_vaporizer";
+                               }
+                       }
+                       return "";
+               }
+               case RANDOM_ITEM_TYPE_POWERUP:
+               {
+                       RandomSelection_Init();
+                       RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_POWERUP_STRENGTH,
+                               autocvar_g_random_loot_strength_probability, 1);
+                       RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_POWERUP_SHIELD,
+                               autocvar_g_random_loot_shield_probability, 1);
+                       RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_POWERUP_FUEL_REGEN,
+                               autocvar_g_random_loot_fuel_regen_probability, 1);
+                       RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_POWERUP_JETPACK,
+                               autocvar_g_random_loot_jetpack_probability, 1);
+                       item_type = RandomSelection_chosen_float;
+                       switch (item_type)
+                       {
+                               case RANDOM_ITEM_SUBTYPE_POWERUP_STRENGTH:
+                               {
+                                       return "item_strength";
+                               }
+                               case RANDOM_ITEM_SUBTYPE_POWERUP_SHIELD:
+                               {
+                                       return "item_invincible";
+                               }
+                               case RANDOM_ITEM_SUBTYPE_POWERUP_FUEL_REGEN:
+                               {
+                                       return "item_fuel_regen";
+                               }
+                               case RANDOM_ITEM_SUBTYPE_POWERUP_JETPACK:
+                               {
+                                       return "item_jetpack";
+                               }
+                       }
+                       return "";
+               }
+       }
+       return "";
+}
+
+/// \brief Spawns a random loot item.
+/// \param[in] position Position of the item.
+/// \return No return.
+void RandomItems_SpawnLootItem(vector position)
+{
+       string class_name = RandomItems_GetRandomLootItemClassName();
+       if (class_name == "")
+       {
+               return;
+       }
+       vector spread = '0 0 0';
+       spread.z = autocvar_g_random_loot_spread / 2;
+       spread += randomvec() * autocvar_g_random_loot_spread;
+       random_items_is_spawning = true;
+       Item_CreateLoot(class_name, position, spread, autocvar_g_random_loot_time);
+       random_items_is_spawning = false;
+}
+
+//============================= Hooks ========================================
+
+REGISTER_MUTATOR(random_items, (autocvar_g_random_items ||
+       autocvar_g_random_loot));
+
+MUTATOR_HOOKFUNCTION(random_items, BuildMutatorsString)
+{
+       M_ARGV(0, string) = strcat(M_ARGV(0, string), ":random_items");
+}
+
+MUTATOR_HOOKFUNCTION(random_items, BuildMutatorsPrettyString)
+{
+       M_ARGV(0, string) = strcat(M_ARGV(0, string), ", Random items");
+}
+
+/// \brief Hook that is called when an item is about to spawn.
+MUTATOR_HOOKFUNCTION(random_items, FilterItem, CBC_ORDER_LAST)
+{
+       //PrintToChatAll("FilterItem");
+       if (!autocvar_g_random_items)
+       {
+               return false;
+       }
+       if (random_items_is_spawning == true)
+       {
+               return false;
+       }
+       entity item = M_ARGV(0, entity);
+       if (Item_IsLoot(item))
+       {
+               return false;
+       }
+       if (RandomItems_ReplaceMapItem(item) == NULL)
+       {
+               return false;
+       }
+       return true;
+}
+
+/// \brief Hook that is called after the player has touched an item.
+MUTATOR_HOOKFUNCTION(random_items, ItemTouched, CBC_ORDER_LAST)
+{
+       //PrintToChatAll("ItemTouched");
+       if (!autocvar_g_random_items)
+       {
+               return;
+       }
+       entity item = M_ARGV(0, entity);
+       if (Item_IsLoot(item))
+       {
+               return;
+       }
+       entity new_item = RandomItems_ReplaceMapItem(item);
+       if (new_item == NULL)
+       {
+               return;
+       }
+       Item_ScheduleRespawn(new_item);
+       delete(item);
+}
+
+/// \brief Hook which is called when the player dies.
+MUTATOR_HOOKFUNCTION(random_items, PlayerDies)
+{
+       //PrintToChatAll("PlayerDies");
+       if (!autocvar_g_random_loot)
+       {
+               return;
+       }
+       entity victim = M_ARGV(2, entity);
+       vector loot_position = victim.origin + '0 0 32';
+       int num_loot_items = floor(autocvar_g_random_loot_min + random() *
+               autocvar_g_random_loot_max);
+       for (int item_index = 0; item_index < num_loot_items; ++item_index)
+       {
+               RandomItems_SpawnLootItem(loot_position);
+       }
+}
index 1a2e92c4ff4b146203198c698cea6ff48bd4b049..e6fa5ddfdbd987033473f4aaf2ad5a6f15e69573 100644 (file)
@@ -879,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())
                {
@@ -906,17 +905,20 @@ void Item_Touch(entity this, entity toucher)
 
        toucher = M_ARGV(1, entity);
 
+       // TODO: Proper way to handle expiring and not expiring loot.
+       // Expiring loot will have strength "ticking" will it's dropped.
+       // Not expiring will not tick.
+       // OTOH, do we really need expiring loot?
        if (this.classname == "droppedweapon")
        {
                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_IsLoot(this))
                {
                        // undo what we did above
                        this.strength_finished += time;
@@ -932,31 +934,41 @@ 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);
+       
+       MUTATOR_CALLHOOK(ItemTouched, this, toucher);
+       if (wasfreed(this))
+       {
+               return;
+       }
 
-       if (this.classname == "droppedweapon")
+       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);
-                                       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);
+                               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)
@@ -964,16 +976,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);
        }
 }
 
@@ -1205,11 +1220,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")
@@ -1219,7 +1232,11 @@ 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)
+               // TODO: Proper way to handle expiring and not expiring loot.
+               // Expiring loot will have strength "ticking" will it's dropped.
+               // Not expiring will not tick.
+               // OTOH, do we really need expiring loot?
+               if (this.strength_finished || this.invincible_finished || this.superweapons_finished)
                {
                        // if item is worthless after a timer, have it expire then
                        this.nextthink = max(this.strength_finished, this.invincible_finished, this.superweapons_finished);
@@ -1426,110 +1443,7 @@ 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)
 {
@@ -1670,31 +1584,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;
index 80385971ab34d40a1ea17dbcc42e73714042aa9a..7eb863e32693a444c10ca97e7579ee1225f37d64 100644 (file)
@@ -52,17 +52,10 @@ void ItemDrawSimple(entity this);
 
 #endif
 #ifdef SVQC
-spawnfunc(item_strength);
-spawnfunc(item_invincible);
-spawnfunc(item_armor_small);
-spawnfunc(item_shells);
-spawnfunc(item_bullets);
-spawnfunc(item_rockets);
 
 float autocvar_sv_simple_items;
 bool ItemSend(entity this, entity to, int sf);
 
-
 bool have_pickup_item(entity this);
 
 const float ITEM_RESPAWN_TICKS = 10;
index abd9933116b2d86af3506acd6013b3648f6796f9..ed2d0a800ebec8281634d5ab4ace72132c864091 100644 (file)
@@ -112,6 +112,7 @@ const int ARC_SF_LOCALMASK =   ARC_SF_START | ARC_SF_WANTDIR | ARC_SF_BEAMDIR;
 .float arc_cooldown; // (dropped arc/player) cooling speed
 .float arc_heat_percent = _STAT(ARC_HEAT);
 .float arc_smoke_sound;
+spawnfunc(weapon_arc);
 #endif
 #ifdef CSQC
 
index 972dcd003f23118654a332337c16904e93ca190d..40e453511dd1968fabac276c460f16f67a96cb8e 100644 (file)
@@ -50,4 +50,6 @@ REGISTER_WEAPON(BLASTER, blaster, NEW(Blaster));
 .float blaster_radius;
 .float blaster_force;
 .float blaster_lifetime;
+
+spawnfunc(weapon_blaster);
 #endif
index e686cfa94cf87cbaf962ba52ecf77fb52a69e520..be6afd82c51c01a088caca071813a441f9f4b649 100644 (file)
@@ -68,4 +68,5 @@ REGISTER_WEAPON(CRYLINK, crylink, NEW(Crylink));
 
 .entity queuenext;
 .entity queueprev;
+spawnfunc(weapon_crylink);
 #endif
index 9c419751173120e17ba80911ea9aca37e9b30026..ebfde371c69f62bbb978811762d20d94e9e37ee8 100644 (file)
@@ -65,4 +65,5 @@ REGISTER_WEAPON(DEVASTATOR, devastator, NEW(Devastator));
 #ifdef SVQC
 .float rl_release;
 .float rl_detonate_later;
+spawnfunc(weapon_devastator);
 #endif
index 07c967c49bee20b1bb4d31b2f6c87801e3dac863..d881908278392ae386f20a6a6cfb3debf3988b51 100644 (file)
@@ -70,5 +70,6 @@ REGISTER_WEAPON(ELECTRO, electro, NEW(Electro));
 #ifdef SVQC
 .float electro_count;
 .float electro_secondarytime;
+spawnfunc(weapon_electro);
 void W_Electro_ExplodeCombo(entity this);
 #endif
index e973d28845cee8ad52c995be9992a5ffd2da3667..cd52d2a70ca5e2f3c11d271a15df40ff2684d827 100644 (file)
@@ -57,4 +57,5 @@ REGISTER_WEAPON(FIREBALL, fireball, NEW(Fireball));
 .float bot_primary_fireballmooth; // whatever a mooth is
 .vector fireball_impactvec;
 .float fireball_primarytime;
+spawnfunc(weapon_fireball);
 #endif
index 24c700cc84d9412bf5362bd6d827656cda909d0f..c5661f1e66831df9576c1ebd0e1fa615aeb7f51f 100644 (file)
@@ -56,3 +56,7 @@ CLASS(Hagar, Weapon)
 
 ENDCLASS(Hagar)
 REGISTER_WEAPON(HAGAR, hagar, NEW(Hagar));
+
+#ifdef SVQC
+spawnfunc(weapon_hagar);
+#endif
index 4664e54d96776a7b02bc3ccdb7d34aa91ebc392c..3ab29907e07aadb236c8b9731eed8f9acbadd5db 100644 (file)
@@ -48,3 +48,7 @@ CLASS(HLAC, Weapon)
 
 ENDCLASS(HLAC)
 REGISTER_WEAPON(HLAC, hlac, NEW(HLAC));
+
+#ifdef SVQC
+spawnfunc(weapon_hlac);
+#endif
index 4988323fda187803dab6218b45002d4bede7bf90..d028323ff1755ffe7d73cf237a127861a1aed66f 100644 (file)
@@ -73,4 +73,5 @@ OffhandHook OFFHAND_HOOK; STATIC_INIT(OFFHAND_HOOK) { OFFHAND_HOOK = NEW(Offhand
 .float hook_refire;
 .float hook_time_hooked;
 .float hook_time_fueldecrease;
+spawnfunc(weapon_hook);
 #endif
index 2f0974971ecc80112eb285e589801f88a074dc71..183a736c2572ebe107f465fa3e0ecf7ed2a8bbe6 100644 (file)
@@ -54,3 +54,7 @@ CLASS(MachineGun, Weapon)
 
 ENDCLASS(MachineGun)
 REGISTER_WEAPON(MACHINEGUN, machinegun, NEW(MachineGun));
+
+#ifdef SVQC
+spawnfunc(weapon_machinegun);
+#endif
index f113e6439e3bea5f42d569e36d86482ff9b9ffe2..7369d8c675a79c64e886086cf5491ecb22938ab0 100644 (file)
@@ -58,4 +58,5 @@ void W_MineLayer_Think(entity this);
 .float minelayer_detonate, mine_explodeanyway;
 .float mine_time;
 .vector mine_orientation;
+spawnfunc(weapon_minelayer);
 #endif
index 4fc5ec9ad2995644c9a72c1f3d268be874f39edf..be9cdbb1f3ef8577285193c13881301cba010faa 100644 (file)
@@ -57,4 +57,5 @@ REGISTER_WEAPON(MORTAR, mortar, NEW(Mortar));
 #ifdef SVQC
 .float gl_detonate_later;
 .float gl_bouncecnt;
+spawnfunc(weapon_mortar);
 #endif
index b46e479aa9f383292498a75e9672cda2013786b4..6af9e3b92fbf7b54addd8fe84a0529ad44e4e0a8 100644 (file)
@@ -41,4 +41,5 @@ REGISTER_WEAPON(PORTO, porto, NEW(PortoLaunch));
 .float porto_v_angle_held;
 .vector right_vector;
 .float porto_forbidden;
+spawnfunc(weapon_porto);
 #endif
index b1c01b86ff861238a106b1d03a2b8dad77d8e55a..0340d9fdb1e87d87e9f18d3bb88b42111ecfb98e 100644 (file)
@@ -50,4 +50,5 @@ REGISTER_WEAPON(RIFLE, rifle, NEW(Rifle));
 
 #ifdef SVQC
 .float rifle_accumulator;
+spawnfunc(weapon_rifle);
 #endif
index 443d0843d01b3e1fea2bba4ba9d11a4cc182ba4d..40ba463ec7366362795881c0fb2ea36528eb2c01 100644 (file)
@@ -85,6 +85,7 @@ REGISTER_WEAPON(SEEKER, seeker, NEW(Seeker));
 #ifdef SVQC
 .entity tag_target, wps_tag_tracker;
 .float tag_time;
+spawnfunc(weapon_seeker);
 
 IntrusiveList g_seeker_trackers;
 STATIC_INIT(g_seeker_trackers) { g_seeker_trackers = IL_NEW(); }
index 89685376dad9a6fd52b6b61f966fdbe2d35ba7ac..d382890684ab5e66d6ddc5af73dc351920289647 100644 (file)
@@ -84,3 +84,7 @@ void Net_ReadShockwaveParticle();
 .float sw_spread_min;
 .float sw_time;
 #endif
+
+#ifdef SVQC
+spawnfunc(weapon_shockwave);
+#endif
index cd646a768f456aa2c74c9bdf8dda6f909ef8b305..f4afbc070c12911b6e942100e7f7a7de1f8e8558 100644 (file)
@@ -52,3 +52,7 @@ CLASS(Shotgun, Weapon)
 
 ENDCLASS(Shotgun)
 REGISTER_WEAPON(SHOTGUN, shotgun, NEW(Shotgun));
+
+#ifdef SVQC
+spawnfunc(weapon_shotgun);
+#endif
index 714a2b8b5853566a8175049433744f69dcdfc4c8..8e5f3b8c0db905cae65fef86c03e1b6a0fed3d04 100644 (file)
@@ -48,3 +48,7 @@ class(Tuba) .float tuba_volume;
 class(Tuba) .float tuba_volume_initial;
 class(Tuba) .int tuba_instrument;
 #endif
+
+#ifdef SVQC
+spawnfunc(weapon_tuba);
+#endif
index 0c5c19200a437d67a063ffe58fd43785557bcafc..874f318633710d90b282b362eafbf4c6a72c0c8a 100644 (file)
@@ -59,4 +59,5 @@ REGISTER_WEAPON(VAPORIZER, vaporizer, NEW(Vaporizer));
 .float rm_force;
 .float rm_damage;
 .float rm_edmg;
+spawnfunc(weapon_vaporizer);
 #endif
index 5a41b90d8efede1e64457ac4001c09c86ea9b7b1..3a4ab52a54a2efcc94537df688a9198f0d486b36 100644 (file)
@@ -61,6 +61,6 @@ REGISTER_WEAPON(VORTEX, vortex, NEW(Vortex));
 
 
 #ifdef SVQC
-
 .float vortex_lasthit;
+spawnfunc(weapon_vortex);
 #endif
index de7e01aa7a862d3f328d0c02a3fdd542e5238ad9..569301c5d65c369b60deb900f44be3bf1447c5bf 100644 (file)
@@ -14,6 +14,7 @@
 #include <server/impulse.qc>
 #include <server/ipban.qc>
 #include <server/item_key.qc>
+#include <server/items.qc>
 #include <server/mapvoting.qc>
 #include <server/matrix.qc>
 #include <server/miscfunctions.qc>
index 67f6aae4db511fd7cb1b91cb1cdb7412c7f017ea..2013fd6bb5db5c521737cf0985fc65c13a43846e 100644 (file)
@@ -14,6 +14,7 @@
 #include <server/impulse.qh>
 #include <server/ipban.qh>
 #include <server/item_key.qh>
+#include <server/items.qh>
 #include <server/mapvoting.qh>
 #include <server/matrix.qh>
 #include <server/miscfunctions.qh>
index 2e2301d0bdec150704ae2b6f297beddbda5870a2..d7dcbf3a803890d7a0c016fac4c324d48017bb7c 100644 (file)
@@ -2,32 +2,11 @@
 
 #include <server/defs.qh>
 #include <server/miscfunctions.qh>
+#include <server/items.qh>
 #include <common/weapons/_all.qh>
 
-spawnfunc(weapon_crylink);
-spawnfunc(weapon_electro);
-spawnfunc(weapon_hagar);
-spawnfunc(weapon_hook);
-spawnfunc(weapon_machinegun);
-spawnfunc(weapon_vortex);
-spawnfunc(weapon_minelayer);
-
 spawnfunc(target_items);
 
-spawnfunc(item_bullets);
-spawnfunc(item_cells);
-spawnfunc(item_rockets);
-spawnfunc(item_shells);
-
-spawnfunc(item_strength);
-
-spawnfunc(item_armor_big);
-spawnfunc(item_armor_mega);
-spawnfunc(item_armor_small);
-
-spawnfunc(item_health_medium);
-spawnfunc(item_health_mega);
-
 //***********************
 //QUAKE 3 ENTITIES - So people can play quake3 maps with the xonotic weapons
 //***********************
index 6c69859fdfe0c6e748acc5b227227f49d5e9626c..39abab09fb323836d71645578ed71eeb2453deea 100644 (file)
@@ -2,34 +2,10 @@
 
 #include <server/defs.qh>
 #include <server/miscfunctions.qh>
+#include <server/items.qh>
 #include <common/weapons/_all.qh>
-// #include <server/mutators/gamemode.qh>
-
-spawnfunc(weapon_arc);
-spawnfunc(weapon_crylink);
-spawnfunc(weapon_electro);
-spawnfunc(weapon_mortar);
-spawnfunc(weapon_hagar);
-spawnfunc(weapon_machinegun);
-spawnfunc(weapon_devastator);
-spawnfunc(weapon_shotgun);
-spawnfunc(weapon_vortex);
-
-spawnfunc(item_armor_big);
-spawnfunc(item_armor_mega);
-spawnfunc(item_armor_small);
-
-spawnfunc(item_bullets);
-spawnfunc(item_cells);
-spawnfunc(item_quad);
-spawnfunc(item_rockets);
-spawnfunc(item_shells);
-
-spawnfunc(item_jetpack);
 
 spawnfunc(item_haste);
-spawnfunc(item_health_medium);
-spawnfunc(item_health_mega);
 spawnfunc(item_invis);
 
 //***********************
@@ -57,6 +33,11 @@ spawnfunc(ammo_boaster)              { spawnfunc_item_cells(this);                   }
 spawnfunc(ammo_betty)          { spawnfunc_item_rockets(this);                 }
 spawnfunc(ammo_imperius)       { spawnfunc_item_cells(this);                   }
 
+spawnfunc(item_quad)
+{
+       this.classname = "item_strength";
+       spawnfunc_item_strength(this);
+}
 spawnfunc(item_padpower)       { spawnfunc_item_quad(this);                    }
 spawnfunc(item_climber)                { spawnfunc_item_invincible(this);              }
 spawnfunc(item_speedy)         { spawnfunc_item_haste(this);                   }
diff --git a/qcsrc/server/items.qc b/qcsrc/server/items.qc
new file mode 100644 (file)
index 0000000..c0fb764
--- /dev/null
@@ -0,0 +1,419 @@
+#include "items.qh"
+
+/// \file
+/// \brief Source file that contains implementation of the functions related to
+/// game items.
+/// \copyright GNU GPLv2 or any later version.
+
+#include <common/mutators/mutator/instagib/sv_instagib.qh>
+
+.bool m_isloot; ///< Holds whether item is loot.
+
+entity Item_Create(string class_name, vector position)
+{
+       entity item = spawn();
+       item.classname = class_name;
+       item.spawnfunc_checked = true;
+       Item_Initialize(item, class_name);
+       if (wasfreed(item))
+       {
+               return NULL;
+       }
+       setorigin(item, position);
+       return item;
+}
+
+void Item_Initialize(entity item, string class_name)
+{
+       switch (class_name)
+       {
+               case "item_health_small":
+               {
+                       spawnfunc_item_health_small(item);
+                       return;
+               }
+               case "item_health_medium":
+               {
+                       spawnfunc_item_health_medium(item);
+                       return;
+               }
+               case "item_health_big":
+               case "item_health_large":
+               {
+                       spawnfunc_item_health_big(item);
+                       return;
+               }
+               case "item_health_mega":
+               {
+                       spawnfunc_item_health_mega(item);
+                       return;
+               }
+               case "item_armor_small":
+               {
+                       spawnfunc_item_armor_small(item);
+                       return;
+               }
+               case "item_armor_medium":
+               {
+                       spawnfunc_item_armor_medium(item);
+                       return;
+               }
+               case "item_armor_big":
+               case "item_armor_large":
+               {
+                       spawnfunc_item_armor_big(item);
+                       return;
+               }
+               case "item_armor_mega":
+               {
+                       spawnfunc_item_armor_mega(item);
+                       return;
+               }
+               case "item_shells":
+               {
+                       spawnfunc_item_shells(item);
+                       return;
+               }
+               case "item_bullets":
+               {
+                       spawnfunc_item_bullets(item);
+                       return;
+               }
+               case "item_rockets":
+               {
+                       spawnfunc_item_rockets(item);
+                       return;
+               }
+               case "item_cells":
+               {
+                       spawnfunc_item_cells(item);
+                       return;
+               }
+               case "item_plasma":
+               {
+                       spawnfunc_item_plasma(item);
+                       return;
+               }
+               case "item_fuel":
+               {
+                       spawnfunc_item_fuel(item);
+                       return;
+               }
+               case "weapon_blaster":
+               case "weapon_laser":
+               {
+                       spawnfunc_weapon_blaster(item);
+                       return;
+               }
+               case "weapon_shotgun":
+               {
+                       spawnfunc_weapon_shotgun(item);
+                       return;
+               }
+               case "weapon_machinegun":
+               case "weapon_uzi":
+               {
+                       spawnfunc_weapon_machinegun(item);
+                       return;
+               }
+               case "weapon_mortar":
+               case "weapon_grenadelauncher":
+               {
+                       spawnfunc_weapon_mortar(item);
+                       return;
+               }
+               case "weapon_electro":
+               {
+                       spawnfunc_weapon_electro(item);
+                       return;
+               }
+               case "weapon_crylink":
+               {
+                       spawnfunc_weapon_crylink(item);
+                       return;
+               }
+               case "weapon_vortex":
+               case "weapon_nex":
+               {
+                       spawnfunc_weapon_vortex(item);
+                       return;
+               }
+               case "weapon_hagar":
+               {
+                       spawnfunc_weapon_hagar(item);
+                       return;
+               }
+               case "weapon_devastator":
+               case "weapon_rocketlauncher":
+               {
+                       spawnfunc_weapon_devastator(item);
+                       return;
+               }
+               case "weapon_shockwave":
+               {
+                       spawnfunc_weapon_shockwave(item);
+                       return;
+               }
+               case "weapon_arc":
+               {
+                       spawnfunc_weapon_arc(item);
+                       return;
+               }
+               case "weapon_hook":
+               {
+                       spawnfunc_weapon_hook(item);
+                       return;
+               }
+               case "weapon_tuba":
+               {
+                       spawnfunc_weapon_tuba(item);
+                       return;
+               }
+               case "weapon_porto":
+               {
+                       spawnfunc_weapon_porto(item);
+                       return;
+               }
+               case "weapon_fireball":
+               {
+                       spawnfunc_weapon_fireball(item);
+                       return;
+               }
+               case "weapon_minelayer":
+               {
+                       spawnfunc_weapon_minelayer(item);
+                       return;
+               }
+               case "weapon_hlac":
+               {
+                       spawnfunc_weapon_hlac(item);
+                       return;
+               }
+               case "weapon_rifle":
+               case "weapon_campingrifle":
+               case "weapon_sniperrifle":
+               {
+                       spawnfunc_weapon_rifle(item);
+                       return;
+               }
+               case "weapon_seeker":
+               {
+                       spawnfunc_weapon_seeker(item);
+                       return;
+               }
+               case "weapon_vaporizer":
+               case "weapon_minstanex":
+               {
+                       spawnfunc_weapon_vaporizer(item);
+                       return;
+               }
+               case "item_strength":
+               {
+                       spawnfunc_item_strength(item);
+                       return;
+               }
+               case "item_invincible":
+               {
+                       spawnfunc_item_invincible(item);
+                       return;
+               }
+               case "item_fuel_regen":
+               {
+                       spawnfunc_item_fuel_regen(item);
+                       return;
+               }
+               case "item_jetpack":
+               {
+                       spawnfunc_item_jetpack(item);
+                       return;
+               }
+               case "item_vaporizer_cells":
+               {
+                       spawnfunc_item_vaporizer_cells(item);
+                       return;
+               }
+               case "item_invisibility":
+               {
+                       instagib_invisibility(item);
+                       return;
+               }
+               case "item_extralife":
+               {
+                       instagib_extralife(item);
+                       return;
+               }
+               case "item_speed":
+               {
+                       instagib_speed(item);
+                       return;
+               }
+       }
+       error("Item_Initialize: Invalid classname ", class_name);
+}
+
+entity Item_CreateLoot(string class_name, vector position, vector vel,
+       float time_to_live)
+{
+       entity item = spawn();
+       if (!Item_InitializeLoot(item, class_name, position, vel, time_to_live))
+       {
+               return NULL;
+       }
+       return item;
+}
+
+bool Item_InitializeLoot(entity item, string class_name, vector position,
+       vector vel, float time_to_live)
+{
+       item.classname = class_name;
+       Item_SetLoot(item, true);
+       item.noalign = true;
+       item.pickup_anyway = true;
+       item.spawnfunc_checked = true;
+       Item_Initialize(item, class_name);
+       if (wasfreed(item))
+       {
+               return false;
+       }
+       item.gravity = 1;
+       setorigin(item, position);
+       item.velocity = vel;
+       SUB_SetFade(item, time + time_to_live, 1);
+       return true;
+}
+
+bool Item_IsLoot(entity item)
+{
+       return item.m_isloot || (item.classname == "droppedweapon");
+}
+
+void Item_SetLoot(entity item, bool loot)
+{
+       item.m_isloot = loot;
+}
+
+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);
+}
+
+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_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_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_rockets)
+{
+       StartItem(this, ITEM_Rockets);
+}
+
+spawnfunc(item_cells)
+{
+       StartItem(this, ITEM_Cells);
+}
+
+spawnfunc(item_plasma)
+{
+       StartItem(this, ITEM_Plasma);
+}
+
+spawnfunc(item_fuel)
+{
+       StartItem(this, ITEM_JetpackFuel);
+}
+
+spawnfunc(item_strength)
+{
+       StartItem(this, ITEM_Strength);
+}
+
+spawnfunc(item_invincible)
+{
+       StartItem(this, ITEM_Shield);
+}
+
+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);
+}
+
+// Compatibility spawn functions
+
+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); }
diff --git a/qcsrc/server/items.qh b/qcsrc/server/items.qh
new file mode 100644 (file)
index 0000000..37b7d10
--- /dev/null
@@ -0,0 +1,75 @@
+/// \file
+/// \brief Header file that describes the functions related to game items.
+/// \copyright GNU GPLv2 or any later version.
+
+#pragma once
+
+/// \brief Creates a new item.
+/// \param[in] class_name Class name of the item.
+/// \param[in] position Position of the item.
+/// \return Item on success, NULL otherwise.
+entity Item_Create(string class_name, vector position);
+
+/// \brief Initializes the item according to classname.
+/// \param[in,out] item Item to initialize.
+/// \param[in] class_name Class name to use.
+/// \return No return.
+/// \nore This function is useful if you want to set some item properties before
+/// initialization.
+void Item_Initialize(entity item, string class_name);
+
+/// \brief Creates a loot item.
+/// \param[in] class_name Class name of the item.
+/// \param[in] position Position of the item.
+/// \param[in] velocity of the item.
+/// \param[in] time_to_live Amount of time after which the item will disappear.
+/// \return Item on success, NULL otherwise.
+entity Item_CreateLoot(string class_name, vector position, vector vel,
+       float time_to_live);
+
+/// \brief Initializes the loot item.
+/// \param[in] class_name Class name of the item.
+/// \param[in] position Position of the item.
+/// \param[in] velocity of the item.
+/// \param[in] time_to_live Amount of time after which the item will disappear.
+/// \return True on success, false otherwise.
+/// \nore This function is useful if you want to set some item properties before
+/// initialization.
+bool Item_InitializeLoot(entity item, string class_name, vector position,
+       vector vel, float time_to_live);
+
+/// \brief Returns whether the item is loot.
+/// \param[in] item Item to check.
+/// \return True if the item is loot, false otherwise.
+bool Item_IsLoot(entity item);
+
+/// \brief Sets the item loot status.
+/// \param[in,out] item Item to adjust.
+/// \param[in] loot Whether item is loot.
+/// \return No return.
+void Item_SetLoot(entity item, bool loot);
+
+// Item spawn functions.
+// If a function is declared like this:
+// spawnfunc(foo);
+// You need to call it like this:
+// spawnfunc_foo(item);
+
+spawnfunc(item_health_small);
+spawnfunc(item_health_medium);
+spawnfunc(item_health_big);
+spawnfunc(item_health_mega);
+spawnfunc(item_armor_small);
+spawnfunc(item_armor_medium);
+spawnfunc(item_armor_big);
+spawnfunc(item_armor_mega);
+spawnfunc(item_shells);
+spawnfunc(item_bullets);
+spawnfunc(item_rockets);
+spawnfunc(item_cells);
+spawnfunc(item_plasma);
+spawnfunc(item_fuel);
+spawnfunc(item_strength);
+spawnfunc(item_invincible);
+spawnfunc(item_fuel_regen);
+spawnfunc(item_jetpack);
index e0c4198cc7adbea3354f350544950a5cf8ac7397..6e3448066e5d49c7d43aac261bb8cf0a6a2f5148 100644 (file)
@@ -645,6 +645,13 @@ enum {
        MUT_ITEMTOUCH_PICKUP // return this flag to have the item "picked up" and taken even after mutator handled it
 };
 
+/** called after the item has been touched. */
+#define EV_ItemTouched(i, o) \
+    /** item */    i(entity, MUTATOR_ARGV_0_entity) \
+    /** toucher */ i(entity, MUTATOR_ARGV_1_entity) \
+    /**/
+MUTATOR_HOOKABLE(ItemTouched, EV_ItemTouched);
+
 /** Called when the amount of entity resources changes. Can be used to override
 resource limit. */
 #define EV_GetResourceLimit(i, o) \