Xonotic QuakeC
The free, fast arena FPS with crisp movement and a wide array of weapons
sv_random_items.qc
Go to the documentation of this file.
1#include "sv_random_items.qh"
2
7
8//============================ Constants ======================================
9
10//======================= Global variables ====================================
11
12// Replace cvars
13
16
17// Map probability cvars
18
21
24
25// Loot
26
31
32// Loot probability cvars
33
36
39
43
44//====================== Forward declarations =================================
45
50 .bool item_property);
51
52//=========================== Public API ======================================
53
55{
57 {
58 return M_ARGV(1, string);
59 }
62}
63
64string RandomItems_GetRandomVanillaItemClassName(string prefix, int types)
65{
66 if (types == 0)
67 {
68 return "";
69 }
70 while (types != 0)
71 {
72 string cvar_name;
74 if (types & RANDOM_ITEM_TYPE_HEALTH)
75 {
76 cvar_name = sprintf("g_%s_health_probability", prefix);
77 if (!(cvar_type(cvar_name) & CVAR_TYPEFLAG_EXISTS))
78 {
79 LOG_WARNF("Random items: cvar %s doesn't exist.", cvar_name);
80 }
81 else
82 {
84 cvar(cvar_name), 1);
85 }
86 }
87 if (types & RANDOM_ITEM_TYPE_ARMOR)
88 {
89 cvar_name = sprintf("g_%s_armor_probability", prefix);
90 if (!(cvar_type(cvar_name) & CVAR_TYPEFLAG_EXISTS))
91 {
92 LOG_WARNF("Random items: cvar %s doesn't exist.", cvar_name);
93 }
94 else
95 {
97 cvar(cvar_name), 1);
98 }
99 }
100 if (types & RANDOM_ITEM_TYPE_RESOURCE)
101 {
102 cvar_name = sprintf("g_%s_resource_probability", prefix);
103 if (!(cvar_type(cvar_name) & CVAR_TYPEFLAG_EXISTS))
104 {
105 LOG_WARNF("Random items: cvar %s doesn't exist.", cvar_name);
106 }
107 else
108 {
110 cvar(cvar_name), 1);
111 }
112 }
113 if (types & RANDOM_ITEM_TYPE_WEAPON)
114 {
115 cvar_name = sprintf("g_%s_weapon_probability", prefix);
116 if (!(cvar_type(cvar_name) & CVAR_TYPEFLAG_EXISTS))
117 {
118 LOG_WARNF("Random items: cvar %s doesn't exist.", cvar_name);
119 }
120 else
121 {
123 }
124 }
125 if (types & RANDOM_ITEM_TYPE_POWERUP)
126 {
127 cvar_name = sprintf("g_%s_powerup_probability", prefix);
128 if (!(cvar_type(cvar_name) & CVAR_TYPEFLAG_EXISTS))
129 {
130 LOG_WARNF("Random items: cvar %s doesn't exist.", cvar_name);
131 }
132 else
133 {
135 }
136 }
137 int item_type = RandomSelection_chosen_float;
138 string class_name = "";
139 switch (item_type)
140 {
142 {
144 prefix, instanceOfHealth);
145 break;
146 }
148 {
150 prefix, instanceOfArmor);
151 break;
152 }
154 {
156 prefix, instanceOfAmmo);
157 break;
158 }
160 {
162 FOREACH(Weapons, it != WEP_Null &&
163 !(it.spawnflags & WEP_FLAG_MUTATORBLOCKED),
164 {
165 cvar_name = sprintf("g_%s_%s_probability", prefix,
166 it.m_canonical_spawnfunc);
167 if (!(cvar_type(cvar_name) & CVAR_TYPEFLAG_EXISTS))
168 {
169 LOG_WARNF("Random items: cvar %s doesn't exist.",
170 cvar_name);
171 continue;
172 }
173 RandomSelection_AddString(it.m_canonical_spawnfunc,
174 cvar(cvar_name), 1);
175 });
177 break;
178 }
180 {
182 prefix, instanceOfPowerup);
183 break;
184 }
185 }
186 if (class_name != "")
187 {
188 return class_name;
189 }
190 types &= ~item_type;
191 }
192 return "";
193}
194
195//========================= Free functions ====================================
196
201{
202 string cvar_name = sprintf("g_random_items_replace_%s", item.classname);
203 if (!(cvar_type(cvar_name) & CVAR_TYPEFLAG_EXISTS))
204 {
205 LOG_WARNF("Random items: cvar %s doesn't exist.", cvar_name);
206 return "";
207 }
208 return cvar_string(cvar_name);
209}
210
212 .bool item_property)
213{
215 FOREACH(Items, it.item_property && (it.spawnflags & ITEM_FLAG_NORMAL) &&
217 {
218 string cvar_name = sprintf("g_%s_%s_probability", prefix,
219 it.m_canonical_spawnfunc);
220 if (!(cvar_type(cvar_name) & CVAR_TYPEFLAG_EXISTS))
221 {
222 LOG_WARNF("Random items: cvar %s doesn't exist.", cvar_name);
223 continue;
224 }
225 RandomSelection_AddString(it.m_canonical_spawnfunc, cvar(cvar_name), 1);
226 });
228}
229
234{
235 //PrintToChatAll(strcat("Replacing ", item.classname));
236 string new_classnames = RandomItems_GetItemReplacementClassNames(item);
237 if (new_classnames == "")
238 {
239 return NULL;
240 }
241 string new_classname;
242 if (new_classnames == "random")
243 {
244 new_classname = RandomItems_GetRandomItemClassName("random_items");
245 if (new_classname == "")
246 {
247 return NULL;
248 }
249 }
250 else
251 {
252 int num_new_classnames = tokenize_console(new_classnames);
253 if (num_new_classnames == 1)
254 {
255 new_classname = new_classnames;
256 }
257 else
258 {
259 int classname_index = floor(random() * num_new_classnames);
260 new_classname = argv(classname_index);
261 }
262 }
263 //PrintToChatAll(strcat("Replacing with ", new_classname));
264 if (new_classname == item.classname)
265 {
266 return NULL;
267 }
269
270 entity new_item = spawn();
271 Item_CopyFields(item, new_item);
272 new_item.classname = strzone(new_classname);
273 new_item.lifetime = -1; // permanent (not loot)
274 if (MUTATOR_IS_ENABLED(ok))
275 new_item.ok_item = true;
276 Item_Initialise(new_item);
277
279
280 return wasfreed(new_item) ? NULL : new_item;
281}
282
287{
288 string class_name = RandomItems_GetRandomItemClassName("random_loot");
289 if (class_name == "")
290 {
291 return;
292 }
293 vector spread = '0 0 0';
294 spread.z = autocvar_g_random_loot_spread / 2;
297
298 entity item = spawn();
299 item.classname = class_name;
300 item.origin = position;
301 item.velocity = spread;
302 item.lifetime = autocvar_g_random_loot_time;
303 if (MUTATOR_IS_ENABLED(ok))
304 item.ok_item = true;
305 Item_Initialise(item);
306
308}
309
310//============================= Hooks ========================================
311
312MUTATOR_HOOKFUNCTION(random_items, BuildMutatorsString)
313{
314 M_ARGV(0, string) = strcat(M_ARGV(0, string), ":random_items");
315}
316
317MUTATOR_HOOKFUNCTION(random_items, BuildMutatorsPrettyString)
318{
319 M_ARGV(0, string) = strcat(M_ARGV(0, string), ", Random items");
320}
321
323MUTATOR_HOOKFUNCTION(random_items, FilterItem, CBC_ORDER_LAST)
324{
325 //PrintToChatAll("FilterItem");
327 {
328 return false;
329 }
330 if (random_items_is_spawning == true)
331 {
332 return false;
333 }
334 entity item = M_ARGV(0, entity);
335 if (ITEM_IS_LOOT(item))
336 {
337 return false;
338 }
339 if (RandomItems_ReplaceMapItem(item) == NULL)
340 {
341 return false;
342 }
343 return true;
344}
345
347MUTATOR_HOOKFUNCTION(random_items, ItemTouched, CBC_ORDER_LAST)
348{
349 //PrintToChatAll("ItemTouched");
351 {
352 return;
353 }
354 entity item = M_ARGV(0, entity);
355 if (ITEM_IS_LOOT(item))
356 {
357 return;
358 }
359 entity new_item = RandomItems_ReplaceMapItem(item);
360 if (new_item == NULL)
361 {
362 return;
363 }
364 Item_ScheduleRespawn(new_item);
365 delete(item);
366}
367
369MUTATOR_HOOKFUNCTION(random_items, PlayerDies)
370{
371 //PrintToChatAll("PlayerDies");
373 {
374 return;
375 }
376 entity victim = M_ARGV(2, entity);
377 vector loot_position = victim.origin + '0 0 32';
378 int num_loot_items = floor(autocvar_g_random_loot_min + random() *
380 for (int item_index = 0; item_index < num_loot_items; ++item_index)
381 {
382 RandomItems_SpawnLootItem(loot_position);
383 }
384}
#define MUTATOR_CALLHOOK(id,...)
Definition base.qh:143
#define MUTATOR_IS_ENABLED(this)
Definition base.qh:193
const int CBC_ORDER_LAST
Definition base.qh:11
#define MUTATOR_HOOKFUNCTION(...)
Definition base.qh:335
var entity(vector mins, vector maxs,.entity tofield) findbox_tofield_OrFallback
@ ITEM_FLAG_NORMAL
Item is usable during normal gameplay.
Definition item.qh:120
#define M_ARGV(x, type)
Definition events.qh:17
float CVAR_TYPEFLAG_EXISTS
#define spawn
#define tokenize_console
Weapons
Definition guide.qh:113
bool instanceOfAmmo
Definition guide.qh:30
bool instanceOfPowerup
Definition guide.qh:33
bool instanceOfHealth
Definition guide.qh:31
bool instanceOfArmor
Definition guide.qh:32
bool Item_Initialise(entity item)
An optimised and generic way to initialise items (loot or permanent)
Definition spawning.qc:27
bool Item_IsDefinitionAllowed(entity definition)
Checks whether the items with the specified definition are allowed to spawn.
Definition spawning.qc:17
#define ITEM_IS_LOOT(item)
Returns whether the item is loot.
Definition spawning.qh:39
#define FOREACH(list, cond, body)
Definition iter.qh:19
#define LOG_WARNF(...)
Definition log.qh:62
float cvar(string name)
float random(void)
const string cvar_string(string name)
vector randomvec(void)
float floor(float f)
string strzone(string s)
string argv(float n)
strcat(_("^F4Countdown stopped!"), "\n^BG", _("Teams are too unbalanced."))
#define NULL
Definition post.qh:14
ERASEABLE void RandomSelection_Init()
Definition random.qc:4
float RandomSelection_chosen_float
Definition random.qh:6
string RandomSelection_chosen_string
Definition random.qh:7
#define RandomSelection_AddFloat(f, weight, priority)
Definition random.qh:15
#define RandomSelection_AddString(s, weight, priority)
Definition random.qh:16
vector
Definition self.qh:92
void Item_ScheduleRespawn(entity e)
Definition items.qc:391
void Item_CopyFields(entity this, entity to)
Definition items.qc:850
float autocvar_g_random_loot_time
Amount of time the loot will stay.
string RandomItems_GetItemReplacementClassNames(entity item)
Returns list of classnames to replace a map item with.
entity RandomItems_ReplaceMapItem(entity item)
Replaces a map item.
bool random_items_is_spawning
Probability of random s spawning as loot.
string RandomItems_GetRandomItemClassNameWithProperty(string prefix,.bool item_property)
Returns a random classname of the item with specific property.
float autocvar_g_random_loot_min
Classnames to replace s with.
string RandomItems_GetRandomItemClassName(string prefix)
Returns a random classname of the item.
float autocvar_g_random_loot_max
Maximum amount of loot items.
string RandomItems_GetRandomVanillaItemClassName(string prefix, int types)
Returns a random classname of the vanilla item.
void RandomItems_SpawnLootItem(vector position)
Spawns a random loot item.
float autocvar_g_random_loot_spread
How far can loot be thrown.
Header file that describes the random items mutator.
bool autocvar_g_random_items
Whether to enable random items.
bool autocvar_g_random_loot
Whether to enable random loot.
@ RANDOM_ITEM_TYPE_RESOURCE
@ RANDOM_ITEM_TYPE_ALL
@ RANDOM_ITEM_TYPE_HEALTH
@ RANDOM_ITEM_TYPE_WEAPON
@ RANDOM_ITEM_TYPE_ARMOR
@ RANDOM_ITEM_TYPE_POWERUP
const int WEP_FLAG_MUTATORBLOCKED
Definition weapon.qh:219