From d79c4230cc705cd8a55129d20ccb131afd036f24 Mon Sep 17 00:00:00 2001 From: Lyberta Date: Thu, 28 Sep 2017 19:34:05 +0300 Subject: [PATCH] Started random items mutator. --- mutators.cfg | 81 ++ qcsrc/common/mutators/mutator/_mod.inc | 1 + qcsrc/common/mutators/mutator/_mod.qh | 1 + .../mutators/mutator/random_items/_mod.inc | 4 + .../mutators/mutator/random_items/_mod.qh | 1 + .../mutator/random_items/sv_random_items.qc | 885 ++++++++++++++++++ qcsrc/common/t_items.qc | 78 +- qcsrc/server/_mod.inc | 1 + qcsrc/server/_mod.qh | 1 + qcsrc/server/items.qc | 18 + qcsrc/server/items.qh | 16 + qcsrc/server/mutators/events.qh | 7 + 12 files changed, 1061 insertions(+), 33 deletions(-) create mode 100644 qcsrc/common/mutators/mutator/random_items/_mod.inc create mode 100644 qcsrc/common/mutators/mutator/random_items/_mod.qh create mode 100644 qcsrc/common/mutators/mutator/random_items/sv_random_items.qc create mode 100644 qcsrc/server/items.qc create mode 100644 qcsrc/server/items.qh diff --git a/mutators.cfg b/mutators.cfg index c57088dd9..a8b611aaa 100644 --- a/mutators.cfg +++ b/mutators.cfg @@ -473,3 +473,84 @@ 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 1 "Whether to randomly replace small health." +set g_random_items_replace_health_medium 1 "Whether to randomly replace medium health." +set g_random_items_replace_health_big 1 "Whether to randomly replace big health." +set g_random_items_replace_health_mega 1 "Whether to randomly replace mega health." +set g_random_items_replace_armor_small 1 "Whether to randomly replace small armor." +set g_random_items_replace_armor_medium 1 "Whether to randomly replace medium armor." +set g_random_items_replace_armor_big 1 "Whether to randomly replace big armor." +set g_random_items_replace_armor_mega 1 "Whether to randomly replace mega armor." +set g_random_items_replace_item_shells 1 "Whether to randomly replace shells." +set g_random_items_replace_item_bullets 1 "Whether to randomly replace bullets." +set g_random_items_replace_item_rockets 1 "Whether to randomly replace rockets." +set g_random_items_replace_item_cells 1 "Whether to randomly replace cells." +set g_random_items_replace_weapon_blaster 1 "Whether to randomly replace blaster." +set g_random_items_replace_weapon_shotgun 1 "Whether to randomly replace shotgun." +set g_random_items_replace_weapon_machinegun 1 "Whether to randomly replace machinegun." +set g_random_items_replace_weapon_mortar 1 "Whether to randomly replace mortar." +set g_random_items_replace_weapon_electro 1 "Whether to randomly replace electro." +set g_random_items_replace_weapon_crylink 1 "Whether to randomly replace crylink." +set g_random_items_replace_weapon_vortex 1 "Whether to randomly replace vortex." +set g_random_items_replace_weapon_hagar 1 "Whether to randomly replace hagar." +set g_random_items_replace_weapon_devastator 1 "Whether to randomly replace devastator." +set g_random_items_replace_weapon_shockwave 1 "Whether to randomly replace shockwave." +set g_random_items_replace_weapon_arc 1 "Whether to randomly replace arc." +set g_random_items_replace_weapon_hook 1 "Whether to randomly replace hook." +set g_random_items_replace_weapon_tuba 1 "Whether to randomly replace tuba." +set g_random_items_replace_weapon_porto 1 "Whether to randomly replace port-o-launch." +set g_random_items_replace_weapon_fireball 1 "Whether to randomly replace fireball." +set g_random_items_replace_weapon_minelayer 1 "Whether to randomly replace mine layer." +set g_random_items_replace_weapon_hlac 1 "Whether to randomly replace HLAC." +set g_random_items_replace_weapon_rifle 1 "Whether to randomly replace rifle." +set g_random_items_replace_weapon_seeker 1 "Whether to randomly replace TAG seeker." +set g_random_items_replace_weapon_vaporizer 1 "Whether to randomly replace vaporizer." +set g_random_items_replace_item_strength 1 "Whether to randomly replace strength." +set g_random_items_replace_item_shield 1 "Whether to randomly replace shield." +set g_random_map_health_probability 1 "Probability of random health items spawning in the map." +set g_random_map_armor_probability 1 "Probability of random armor items spawning in the map." +set g_random_map_ammo_probability 1 "Probability of random ammo items spawning in the map." +set g_random_map_weapon_probability 1 "Probability of random weapons spawning in the map." +set g_random_map_powerup_probability 0.25 "Probability of random powerups spawning in the map." +set g_random_map_health_small_probability 10 "Probability of random small health spawning in the map." +set g_random_map_health_medium_probability 4 "Probability of random medium health spawning in the map." +set g_random_map_health_big_probability 2 "Probability of random big health spawning in the map." +set g_random_map_health_mega_probability 1 "Probability of random mega health spawning in the map." +set g_random_map_armor_small_probability 10 "Probability of random small armor spawning in the map." +set g_random_map_armor_medium_probability 4 "Probability of random medium armor spawning in the map." +set g_random_map_armor_big_probability 2 "Probability of random big armor spawning in the map." +set g_random_map_armor_mega_probability 1 "Probability of random mega armor spawning in the map." +set g_random_map_ammo_shells_probability 1 "Probability of random shells spawning in the map." +set g_random_map_ammo_bullets_probability 1 "Probability of random bullets spawning in the map." +set g_random_map_ammo_rockets_probability 1 "Probability of random rockets spawning in the map." +set g_random_map_ammo_cells_probability 1 "Probability of random cells spawning in the map." +set g_random_map_weapon_blaster_probability 0 "Probability of random blaster spawning in the map." +set g_random_map_weapon_shotgun_probability 0 "Probability of random shotgun spawning in the map." +set g_random_map_weapon_machinegun_probability 1 "Probability of random machinegun spawning in the map." +set g_random_map_weapon_mortar_probability 1 "Probability of random mortar spawning in the map." +set g_random_map_weapon_electro_probability 1 "Probability of random electro spawning in the map." +set g_random_map_weapon_crylink_probability 1 "Probability of random crylink spawning in the map." +set g_random_map_weapon_vortex_probability 1 "Probability of random vortex spawning in the map." +set g_random_map_weapon_hagar_probability 1 "Probability of random hagar spawning in the map." +set g_random_map_weapon_devastator_probability 1 "Probability of random devastator spawning in the map." +set g_random_map_weapon_shockwave_probability 0 "Probability of random shockwave spawning in the map." +set g_random_map_weapon_arc_probability 0 "Probability of random arc spawning in the map." +set g_random_map_weapon_hook_probability 0 "Probability of random hook spawning in the map." +set g_random_map_weapon_tuba_probability 0 "Probability of random tuba spawning in the map." +set g_random_map_weapon_porto_probability 0 "Probability of random port-o-launch spawning in the map." +set g_random_map_weapon_fireball_probability 0 "Probability of random fireball spawning in the map." +set g_random_map_weapon_minelayer_probability 0 "Probability of random mine layer spawning in the map." +set g_random_map_weapon_hlac_probability 0 "Probability of random HLAC spawning in the map." +set g_random_map_weapon_rifle_probability 0 "Probability of random rifle spawning in the map." +set g_random_map_weapon_seeker_probability 0 "Probability of random TAG seeker spawning in the map." +set g_random_map_weapon_vaporizer_probability 0 "Probability of random vaporizer spawning in the map." +set g_random_map_strength_probability 1 "Probability of random strength spawning in the map." +set g_random_map_shield_probability 1 "Probability of random shield spawning in the map." +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." diff --git a/qcsrc/common/mutators/mutator/_mod.inc b/qcsrc/common/mutators/mutator/_mod.inc index eeb93ba5e..59b2c117d 100644 --- a/qcsrc/common/mutators/mutator/_mod.inc +++ b/qcsrc/common/mutators/mutator/_mod.inc @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include diff --git a/qcsrc/common/mutators/mutator/_mod.qh b/qcsrc/common/mutators/mutator/_mod.qh index 956c0d975..b1c627fb6 100644 --- a/qcsrc/common/mutators/mutator/_mod.qh +++ b/qcsrc/common/mutators/mutator/_mod.qh @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include diff --git a/qcsrc/common/mutators/mutator/random_items/_mod.inc b/qcsrc/common/mutators/mutator/random_items/_mod.inc new file mode 100644 index 000000000..191ea09d5 --- /dev/null +++ b/qcsrc/common/mutators/mutator/random_items/_mod.inc @@ -0,0 +1,4 @@ +// generated file; do not modify +#ifdef SVQC + #include +#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 index 000000000..98fb4815c --- /dev/null +++ b/qcsrc/common/mutators/mutator/random_items/_mod.qh @@ -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 index 000000000..48b304326 --- /dev/null +++ b/qcsrc/common/mutators/mutator/random_items/sv_random_items.qc @@ -0,0 +1,885 @@ +/// \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_AMMO, + 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_AMMO_SHELLS, + RANDOM_ITEM_SUBTYPE_AMMO_BULLETS, + RANDOM_ITEM_SUBTYPE_AMMO_ROCKETS, + RANDOM_ITEM_SUBTYPE_AMMO_CELLS +}; + +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 +}; + +//======================= Global variables ==================================== + +bool autocvar_g_random_items; ///< Whether to enable random items. + +// Replace cvars + +/// \brief Whether to randomly replace small health. +bool autocvar_g_random_items_replace_health_small; +/// \brief Whether to randomly replace medium health. +bool autocvar_g_random_items_replace_health_medium; +/// \brief Whether to randomly replace big health. +bool autocvar_g_random_items_replace_health_big; +/// \brief Whether to randomly replace mega health. +bool autocvar_g_random_items_replace_health_mega; + +/// \brief Whether to randomly replace small armor. +bool autocvar_g_random_items_replace_armor_small; +/// \brief Whether to randomly replace medium armor. +bool autocvar_g_random_items_replace_armor_medium; +/// \brief Whether to randomly replace big armor. +bool autocvar_g_random_items_replace_armor_big; +/// \brief Whether to randomly replace mega armor. +bool autocvar_g_random_items_replace_armor_mega; + +/// \brief Whether to randomly replace shells. +bool autocvar_g_random_items_replace_item_shells; +/// \brief Whether to randomly replace bullets. +bool autocvar_g_random_items_replace_item_bullets; +/// \brief Whether to randomly replace rockets. +bool autocvar_g_random_items_replace_item_rockets; +/// \brief Whether to randomly replace cells. +bool autocvar_g_random_items_replace_item_cells; + +/// \brief Whether to randomly replace blaster. +bool autocvar_g_random_items_replace_weapon_blaster; +/// \brief Whether to randomly replace shotgun. +bool autocvar_g_random_items_replace_weapon_shotgun; +/// \brief Whether to randomly replace machinegun. +bool autocvar_g_random_items_replace_weapon_machinegun; +/// \brief Whether to randomly replace mortar. +bool autocvar_g_random_items_replace_weapon_mortar; +/// \brief Whether to randomly replace electro. +bool autocvar_g_random_items_replace_weapon_electro; +/// \brief Whether to randomly replace crylink. +bool autocvar_g_random_items_replace_weapon_crylink; +/// \brief Whether to randomly replace vortex. +bool autocvar_g_random_items_replace_weapon_vortex; +/// \brief Whether to randomly replace hagar. +bool autocvar_g_random_items_replace_weapon_hagar; +/// \brief Whether to randomly replace devastator. +bool autocvar_g_random_items_replace_weapon_devastator; +/// \brief Whether to randomly replace shockwave. +bool autocvar_g_random_items_replace_weapon_shockwave; +/// \brief Whether to randomly replace arc. +bool autocvar_g_random_items_replace_weapon_arc; +/// \brief Whether to randomly replace hook. +bool autocvar_g_random_items_replace_weapon_hook; +/// \brief Whether to randomly replace tuba. +bool autocvar_g_random_items_replace_weapon_tuba; +/// \brief Whether to randomly replace port-o-launch. +bool autocvar_g_random_items_replace_weapon_porto; +/// \brief Whether to randomly replace fireball. +bool autocvar_g_random_items_replace_weapon_fireball; +/// \brief Whether to randomly replace mine layer. +bool autocvar_g_random_items_replace_weapon_minelayer; +/// \brief Whether to randomly replace HLAC. +bool autocvar_g_random_items_replace_weapon_hlac; +/// \brief Whether to randomly replace rifle. +bool autocvar_g_random_items_replace_weapon_rifle; +/// \brief Whether to randomly replace TAG seeker. +bool autocvar_g_random_items_replace_weapon_seeker; +/// \brief Whether to randomly replace vaporizer. +bool autocvar_g_random_items_replace_weapon_vaporizer; + +/// \brief Whether to randomly replace strength. +bool autocvar_g_random_items_replace_item_strength; +/// \brief Whether to randomly replace shield. +bool autocvar_g_random_items_replace_item_shield; + +// Map probability cvars + +/// \brief Probability of random health items spawning in the map. +float autocvar_g_random_map_health_probability; +/// \brief Probability of random armor items spawning in the map. +float autocvar_g_random_map_armor_probability; +/// \brief Probability of random ammo items spawning in the map. +float autocvar_g_random_map_ammo_probability; +/// \brief Probability of random weapons spawning in the map. +float autocvar_g_random_map_weapon_probability; +/// \brief Probability of random powerups spawning in the map. +float autocvar_g_random_map_powerup_probability; + +/// \brief Probability of random small health spawning in the map. +float autocvar_g_random_map_health_small_probability; +/// \brief Probability of random medium health spawning in the map. +float autocvar_g_random_map_health_medium_probability; +/// \brief Probability of random big health spawning in the map. +float autocvar_g_random_map_health_big_probability; +/// \brief Probability of random mega health spawning in the map. +float autocvar_g_random_map_health_mega_probability; + +/// \brief Probability of random small armor spawning in the map. +float autocvar_g_random_map_armor_small_probability; +/// \brief Probability of random medium armor.spawning in the map. +float autocvar_g_random_map_armor_medium_probability; +/// \brief Probability of random big armor spawning in the map. +float autocvar_g_random_map_armor_big_probability; +/// \brief Probability of random mega armor spawning in the map. +float autocvar_g_random_map_armor_mega_probability; + +/// \brief Probability of random shells spawning in the map. +float autocvar_g_random_map_ammo_shells_probability; +/// \brief Probability of random bullets spawning in the map. +float autocvar_g_random_map_ammo_bullets_probability; +/// \brief Probability of random rockets spawning in the map. +float autocvar_g_random_map_ammo_rockets_probability; +/// \brief Probability of random cells spawning in the map. +float autocvar_g_random_map_ammo_cells_probability; + +/// \brief Probability of random blaster spawning in the map. +float autocvar_g_random_map_weapon_blaster_probability; +/// \brief Probability of random shotgun spawning in the map. +float autocvar_g_random_map_weapon_shotgun_probability; +/// \brief Probability of random machinegun spawning in the map. +float autocvar_g_random_map_weapon_machinegun_probability; +/// \brief Probability of random mortar spawning in the map. +float autocvar_g_random_map_weapon_mortar_probability; +/// \brief Probability of random electro spawning in the map. +float autocvar_g_random_map_weapon_electro_probability; +/// \brief Probability of random crylink spawning in the map. +float autocvar_g_random_map_weapon_crylink_probability; +/// \brief Probability of random vortex spawning in the map. +float autocvar_g_random_map_weapon_vortex_probability; +/// \brief Probability of random hagar spawning in the map. +float autocvar_g_random_map_weapon_hagar_probability; +/// \brief Probability of random devastator spawning in the map. +float autocvar_g_random_map_weapon_devastator_probability; +/// \brief Probability of random shockwave spawning in the map. +float autocvar_g_random_map_weapon_shockwave_probability; +/// \brief Probability of random arc spawning in the map. +float autocvar_g_random_map_weapon_arc_probability; +/// \brief Probability of random hook spawning in the map. +float autocvar_g_random_map_weapon_hook_probability; +/// \brief Probability of random tuba spawning in the map. +float autocvar_g_random_map_weapon_tuba_probability; +/// \brief Probability of random port-o-launch spawning in the map. +float autocvar_g_random_map_weapon_porto_probability; +/// \brief Probability of random fireball spawning in the map. +float autocvar_g_random_map_weapon_fireball_probability; +/// \brief Probability of random mine layer spawning in the map. +float autocvar_g_random_map_weapon_minelayer_probability; +/// \brief Probability of random HLAC spawning in the map. +float autocvar_g_random_map_weapon_hlac_probability; +/// \brief Probability of random rifle spawning in the map. +float autocvar_g_random_map_weapon_rifle_probability; +/// \brief Probability of random TAG seeker spawning in the map. +float autocvar_g_random_map_weapon_seeker_probability; +/// \brief Probability of random vaporizer spawning in the map. +float autocvar_g_random_map_weapon_vaporizer_probability; + +/// \brief Probability of random strength spawning in the map. +float autocvar_g_random_map_strength_probability; +/// \brief Probability of random shield spawning in the map. +float autocvar_g_random_map_shield_probability; + +// 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. + +/// \brief Holds whether random item is spawning. Used to prevent infinite +/// recursion. +bool random_items_is_spawning = false; + +//========================= Free functions ==================================== + +bool RandomItems_ShouldReplaceItem(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 "weapon_blaster": + { + 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_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_nex": + { + return autocvar_g_random_items_replace_weapon_vortex; + } + case "weapon_hagar": + { + return autocvar_g_random_items_replace_weapon_hagar; + } + 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": + { + return autocvar_g_random_items_replace_weapon_rifle; + } + case "weapon_seeker": + { + return autocvar_g_random_items_replace_weapon_seeker; + } + case "weapon_vaporizer": + { + 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 "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 false; + } + } + } + default: + { + return false; + } + } +} + +entity RandomItems_SpawnItem(vector position) +{ + random_items_is_spawning = true; + RandomSelection_Init(); + RandomSelection_AddFloat(RANDOM_ITEM_TYPE_HEALTH, + autocvar_g_random_map_health_probability, 1); + RandomSelection_AddFloat(RANDOM_ITEM_TYPE_ARMOR, + autocvar_g_random_map_armor_probability, 1); + RandomSelection_AddFloat(RANDOM_ITEM_TYPE_AMMO, + autocvar_g_random_map_ammo_probability, 1); + RandomSelection_AddFloat(RANDOM_ITEM_TYPE_WEAPON, + autocvar_g_random_map_weapon_probability, 1); + RandomSelection_AddFloat(RANDOM_ITEM_TYPE_POWERUP, + autocvar_g_random_map_powerup_probability, 1); + int item_type = RandomSelection_chosen_float; + entity item = NULL; + switch (item_type) + { + case RANDOM_ITEM_TYPE_HEALTH: + { + RandomSelection_Init(); + RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_HEALTH_SMALL, + autocvar_g_random_map_health_small_probability, 1); + RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_HEALTH_MEDIUM, + autocvar_g_random_map_health_medium_probability, 1); + RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_HEALTH_BIG, + autocvar_g_random_map_health_big_probability, 1); + RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_HEALTH_MEGA, + autocvar_g_random_map_health_mega_probability, 1); + item_type = RandomSelection_chosen_float; + switch (item_type) + { + case RANDOM_ITEM_SUBTYPE_HEALTH_SMALL: + { + item = new(item_health_small); + item.spawnfunc_checked = true; + spawnfunc_item_health_small(item); + break; + } + case RANDOM_ITEM_SUBTYPE_HEALTH_MEDIUM: + { + item = new(item_health_medium); + item.spawnfunc_checked = true; + spawnfunc_item_health_medium(item); + break; + } + case RANDOM_ITEM_SUBTYPE_HEALTH_BIG: + { + item = new(item_health_big); + item.spawnfunc_checked = true; + spawnfunc_item_health_big(item); + break; + } + case RANDOM_ITEM_SUBTYPE_HEALTH_MEGA: + { + item = new(item_health_mega); + item.spawnfunc_checked = true; + spawnfunc_item_health_mega(item); + break; + } + } + break; + } + case RANDOM_ITEM_TYPE_ARMOR: + { + RandomSelection_Init(); + RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_ARMOR_SMALL, + autocvar_g_random_map_armor_small_probability, 1); + RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_ARMOR_MEDIUM, + autocvar_g_random_map_armor_medium_probability, 1); + RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_ARMOR_BIG, + autocvar_g_random_map_armor_big_probability, 1); + RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_ARMOR_MEGA, + autocvar_g_random_map_armor_mega_probability, 1); + item_type = RandomSelection_chosen_float; + switch (item_type) + { + case RANDOM_ITEM_SUBTYPE_ARMOR_SMALL: + { + item = new(item_armor_small); + item.spawnfunc_checked = true; + spawnfunc_item_armor_small(item); + break; + } + case RANDOM_ITEM_SUBTYPE_ARMOR_MEDIUM: + { + item = new(item_armor_medium); + item.spawnfunc_checked = true; + spawnfunc_item_armor_medium(item); + break; + } + case RANDOM_ITEM_SUBTYPE_ARMOR_BIG: + { + item = new(item_armor_big); + item.spawnfunc_checked = true; + spawnfunc_item_armor_big(item); + break; + } + case RANDOM_ITEM_SUBTYPE_ARMOR_MEGA: + { + item = new(item_armor_mega); + item.spawnfunc_checked = true; + spawnfunc_item_armor_mega(item); + break; + } + } + break; + } + case RANDOM_ITEM_TYPE_AMMO: + { + RandomSelection_Init(); + RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_AMMO_SHELLS, + autocvar_g_random_map_ammo_shells_probability, 1); + RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_AMMO_BULLETS, + autocvar_g_random_map_ammo_bullets_probability, 1); + RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_AMMO_ROCKETS, + autocvar_g_random_map_ammo_rockets_probability, 1); + RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_AMMO_CELLS, + autocvar_g_random_map_ammo_cells_probability, 1); + item_type = RandomSelection_chosen_float; + switch (item_type) + { + case RANDOM_ITEM_SUBTYPE_AMMO_SHELLS: + { + item = new(item_shells); + item.spawnfunc_checked = true; + spawnfunc_item_shells(item); + break; + } + case RANDOM_ITEM_SUBTYPE_AMMO_BULLETS: + { + item = new(item_bullets); + item.spawnfunc_checked = true; + spawnfunc_item_bullets(item); + break; + } + case RANDOM_ITEM_SUBTYPE_AMMO_ROCKETS: + { + item = new(item_rockets); + item.spawnfunc_checked = true; + spawnfunc_item_rockets(item); + break; + } + case RANDOM_ITEM_SUBTYPE_AMMO_CELLS: + { + item = new(item_cells); + item.spawnfunc_checked = true; + spawnfunc_item_cells(item); + break; + } + } + break; + } + case RANDOM_ITEM_TYPE_WEAPON: + { + RandomSelection_Init(); + RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_WEAPON_BLASTER, + autocvar_g_random_map_weapon_blaster_probability, 1); + RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_WEAPON_SHOTGUN, + autocvar_g_random_map_weapon_shotgun_probability, 1); + RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_WEAPON_MACHINEGUN, + autocvar_g_random_map_weapon_machinegun_probability, 1); + RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_WEAPON_MORTAR, + autocvar_g_random_map_weapon_mortar_probability, 1); + RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_WEAPON_ELECTRO, + autocvar_g_random_map_weapon_electro_probability, 1); + RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_WEAPON_CRYLINK, + autocvar_g_random_map_weapon_crylink_probability, 1); + RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_WEAPON_VORTEX, + autocvar_g_random_map_weapon_vortex_probability, 1); + RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_WEAPON_HAGAR, + autocvar_g_random_map_weapon_hagar_probability, 1); + RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_WEAPON_DEVASTATOR, + autocvar_g_random_map_weapon_devastator_probability, 1); + RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_WEAPON_SHOCKWAVE, + autocvar_g_random_map_weapon_shockwave_probability, 1); + RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_WEAPON_ARC, + autocvar_g_random_map_weapon_arc_probability, 1); + RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_WEAPON_HOOK, + autocvar_g_random_map_weapon_hook_probability, 1); + RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_WEAPON_TUBA, + autocvar_g_random_map_weapon_tuba_probability, 1); + RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_WEAPON_PORTO, + autocvar_g_random_map_weapon_porto_probability, 1); + RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_WEAPON_FIREBALL, + autocvar_g_random_map_weapon_fireball_probability, 1); + RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_WEAPON_MINELAYER, + autocvar_g_random_map_weapon_minelayer_probability, 1); + RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_WEAPON_HLAC, + autocvar_g_random_map_weapon_hlac_probability, 1); + RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_WEAPON_RIFLE, + autocvar_g_random_map_weapon_rifle_probability, 1); + RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_WEAPON_SEEKER, + autocvar_g_random_map_weapon_seeker_probability, 1); + RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_WEAPON_VAPORIZER, + autocvar_g_random_map_weapon_vaporizer_probability, 1); + item_type = RandomSelection_chosen_float; + switch (item_type) + { + case RANDOM_ITEM_SUBTYPE_WEAPON_BLASTER: + { + item = new(weapon_blaster); + item.spawnfunc_checked = true; + spawnfunc_weapon_blaster(item); + break; + } + case RANDOM_ITEM_SUBTYPE_WEAPON_SHOTGUN: + { + item = new(weapon_shotgun); + item.spawnfunc_checked = true; + spawnfunc_weapon_shotgun(item); + break; + } + case RANDOM_ITEM_SUBTYPE_WEAPON_MACHINEGUN: + { + item = new(weapon_machinegun); + item.spawnfunc_checked = true; + spawnfunc_weapon_machinegun(item); + break; + } + case RANDOM_ITEM_SUBTYPE_WEAPON_MORTAR: + { + item = new(weapon_grenadelauncher); + item.spawnfunc_checked = true; + spawnfunc_weapon_grenadelauncher(item); + break; + } + case RANDOM_ITEM_SUBTYPE_WEAPON_ELECTRO: + { + item = new(weapon_electro); + item.spawnfunc_checked = true; + spawnfunc_weapon_electro(item); + break; + } + case RANDOM_ITEM_SUBTYPE_WEAPON_CRYLINK: + { + item = new(weapon_crylink); + item.spawnfunc_checked = true; + spawnfunc_weapon_crylink(item); + break; + } + case RANDOM_ITEM_SUBTYPE_WEAPON_VORTEX: + { + item = new(weapon_nex); + item.spawnfunc_checked = true; + spawnfunc_weapon_nex(item); + break; + } + case RANDOM_ITEM_SUBTYPE_WEAPON_HAGAR: + { + item = new(weapon_hagar); + item.spawnfunc_checked = true; + spawnfunc_weapon_hagar(item); + break; + } + case RANDOM_ITEM_SUBTYPE_WEAPON_DEVASTATOR: + { + item = new(weapon_rocketlauncher); + item.spawnfunc_checked = true; + spawnfunc_weapon_rocketlauncher(item); + break; + } + case RANDOM_ITEM_SUBTYPE_WEAPON_SHOCKWAVE: + { + item = new(weapon_shockwave); + item.spawnfunc_checked = true; + spawnfunc_weapon_shockwave(item); + break; + } + case RANDOM_ITEM_SUBTYPE_WEAPON_ARC: + { + item = new(weapon_arc); + item.spawnfunc_checked = true; + spawnfunc_weapon_arc(item); + break; + } + case RANDOM_ITEM_SUBTYPE_WEAPON_HOOK: + { + item = new(weapon_hook); + item.spawnfunc_checked = true; + spawnfunc_weapon_hook(item); + break; + } + case RANDOM_ITEM_SUBTYPE_WEAPON_TUBA: + { + item = new(weapon_tuba); + item.spawnfunc_checked = true; + spawnfunc_weapon_tuba(item); + break; + } + case RANDOM_ITEM_SUBTYPE_WEAPON_PORTO: + { + item = new(weapon_porto); + item.spawnfunc_checked = true; + spawnfunc_weapon_porto(item); + break; + } + case RANDOM_ITEM_SUBTYPE_WEAPON_FIREBALL: + { + item = new(weapon_fireball); + item.spawnfunc_checked = true; + spawnfunc_weapon_fireball(item); + break; + } + case RANDOM_ITEM_SUBTYPE_WEAPON_MINELAYER: + { + item = new(weapon_minelayer); + item.spawnfunc_checked = true; + spawnfunc_weapon_minelayer(item); + break; + } + case RANDOM_ITEM_SUBTYPE_WEAPON_HLAC: + { + item = new(weapon_hlac); + item.spawnfunc_checked = true; + spawnfunc_weapon_hlac(item); + break; + } + case RANDOM_ITEM_SUBTYPE_WEAPON_RIFLE: + { + item = new(weapon_rifle); + item.spawnfunc_checked = true; + spawnfunc_weapon_rifle(item); + break; + } + case RANDOM_ITEM_SUBTYPE_WEAPON_SEEKER: + { + item = new(weapon_seeker); + item.spawnfunc_checked = true; + spawnfunc_weapon_seeker(item); + break; + } + case RANDOM_ITEM_SUBTYPE_WEAPON_VAPORIZER: + { + item = new(weapon_vaporizer); + item.spawnfunc_checked = true; + spawnfunc_weapon_vaporizer(item); + break; + } + } + break; + } + case RANDOM_ITEM_TYPE_POWERUP: + { + RandomSelection_Init(); + RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_POWERUP_STRENGTH, + autocvar_g_random_map_strength_probability, 1); + RandomSelection_AddFloat(RANDOM_ITEM_SUBTYPE_POWERUP_SHIELD, + autocvar_g_random_map_shield_probability, 1); + item_type = RandomSelection_chosen_float; + switch (item_type) + { + case RANDOM_ITEM_SUBTYPE_POWERUP_STRENGTH: + { + item = new(item_strength); + item.spawnfunc_checked = true; + spawnfunc_item_strength(item); + break; + } + case RANDOM_ITEM_SUBTYPE_POWERUP_SHIELD: + { + item = new(item_invincible); + item.spawnfunc_checked = true; + spawnfunc_item_invincible(item); + break; + } + } + break; + } + } + random_items_is_spawning = false; + if (wasfreed(item)) + { + return NULL; + } + setorigin(item, position); + return item; +} + +//============================= Hooks ======================================== + +REGISTER_MUTATOR(random_items, autocvar_g_random_items); + +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) +{ + //PrintToChatAll("FilterItem"); + if (random_items_is_spawning == true) + { + return false; + } + entity item = M_ARGV(0, entity); + if (Item_IsLoot(item)) + { + return false; + } + if (!RandomItems_ShouldReplaceItem(item)) + { + return false; + } + if (RandomItems_SpawnItem(item.origin) == 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"); + entity item = M_ARGV(0, entity); + if (Item_IsLoot(item)) + { + return; + } + if (!RandomItems_ShouldReplaceItem(item)) + { + return; + } + entity new_item = RandomItems_SpawnItem(item.origin); + 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"); + entity victim = M_ARGV(2, entity); + 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) + { + entity loot = RandomItems_SpawnItem(victim.origin); + if (loot == NULL) + { + continue; + } + Item_SetLoot(loot, true); + set_movetype(loot, MOVETYPE_TOSS); + loot.gravity = 1; + loot.reset = SUB_Remove; + setorigin(loot, victim.origin + '0 0 32'); + loot.velocity = '0 0 200' + randomvec() * 500; + SUB_SetFade(loot, time + autocvar_g_random_loot_time, 1); + } +} diff --git a/qcsrc/common/t_items.qc b/qcsrc/common/t_items.qc index 1a2e92c4f..0d9418ede 100644 --- a/qcsrc/common/t_items.qc +++ b/qcsrc/common/t_items.qc @@ -881,7 +881,7 @@ 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,7 +906,7 @@ void Item_Touch(entity this, entity toucher) toucher = M_ARGV(1, entity); - if (this.classname == "droppedweapon") + if (Item_IsLoot(this)) { this.strength_finished = max(0, this.strength_finished - time); this.invincible_finished = max(0, this.invincible_finished - time); @@ -916,7 +916,7 @@ void Item_Touch(entity this, entity toucher) bool gave = ITEM_HANDLE(Pickup, it, this, toucher); if (!gave) { - if (this.classname == "droppedweapon") + if (Item_IsLoot(this)) { // undo what we did above this.strength_finished += time; @@ -932,31 +932,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 +974,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,8 +1218,7 @@ 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 diff --git a/qcsrc/server/_mod.inc b/qcsrc/server/_mod.inc index de7e01aa7..569301c5d 100644 --- a/qcsrc/server/_mod.inc +++ b/qcsrc/server/_mod.inc @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include diff --git a/qcsrc/server/_mod.qh b/qcsrc/server/_mod.qh index 67f6aae4d..2013fd6bb 100644 --- a/qcsrc/server/_mod.qh +++ b/qcsrc/server/_mod.qh @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include diff --git a/qcsrc/server/items.qc b/qcsrc/server/items.qc new file mode 100644 index 000000000..59c437e35 --- /dev/null +++ b/qcsrc/server/items.qc @@ -0,0 +1,18 @@ +#include "items.qh" + +/// \file +/// \brief Source file that contains implementation of the functions related to +/// game items. +/// \copyright GNU GPLv2 or any later version. + +.bool m_isloot; ///< Holds whether item is loot. + +bool Item_IsLoot(entity e) +{ + return e.m_isloot || (e.classname == "droppedweapon"); +} + +void Item_SetLoot(entity e, bool isloot) +{ + e.m_isloot = isloot; +} diff --git a/qcsrc/server/items.qh b/qcsrc/server/items.qh new file mode 100644 index 000000000..2e4dfd47e --- /dev/null +++ b/qcsrc/server/items.qh @@ -0,0 +1,16 @@ +/// \file +/// \brief Header file that describes the functions related to game items. +/// \copyright GNU GPLv2 or any later version. + +#pragma once + +/// \brief Returns whether item is loot. +/// \param[in] item Item to check. +/// \return True if 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); diff --git a/qcsrc/server/mutators/events.qh b/qcsrc/server/mutators/events.qh index e0c4198cc..6e3448066 100644 --- a/qcsrc/server/mutators/events.qh +++ b/qcsrc/server/mutators/events.qh @@ -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) \ -- 2.39.2