Xonotic
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 
64 string 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  {
83  RandomSelection_AddFloat(RANDOM_ITEM_TYPE_HEALTH,
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  {
96  RandomSelection_AddFloat(RANDOM_ITEM_TYPE_ARMOR,
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  {
109  RandomSelection_AddFloat(RANDOM_ITEM_TYPE_RESOURCE,
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  {
122  RandomSelection_AddFloat(RANDOM_ITEM_TYPE_WEAPON, cvar(cvar_name), 1);
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  {
134  RandomSelection_AddFloat(RANDOM_ITEM_TYPE_POWERUP, cvar(cvar_name), 1);
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  });
176  class_name = RandomSelection_chosen_string;
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  entity new_item;
270  if (!MUTATOR_IS_ENABLED(ok))
271  {
272  new_item = Item_Create(strzone(new_classname), item.origin,
274  random_items_is_spawning = false;
275  if (new_item == NULL)
276  {
277  return NULL;
278  }
279  }
280  else
281  {
282  new_item = spawn();
283  new_item.classname = strzone(new_classname);
284  new_item.spawnfunc_checked = true;
285  new_item.noalign = Item_ShouldKeepPosition(item);
286  new_item.ok_item = true;
287  Item_Initialize(new_item, new_classname);
288  random_items_is_spawning = false;
289  if (wasfreed(new_item))
290  {
291  return NULL;
292  }
293  setorigin(new_item, item.origin);
294  }
295  if (item.team)
296  {
297  new_item.team = item.team;
298  }
299  return new_item;
300 }
301 
306 {
307  string class_name = RandomItems_GetRandomItemClassName("random_loot");
308  if (class_name == "")
309  {
310  return;
311  }
312  vector spread = '0 0 0';
313  spread.z = autocvar_g_random_loot_spread / 2;
316  if (!MUTATOR_IS_ENABLED(ok))
317  {
318  Item_CreateLoot(class_name, position, spread,
320  }
321  else
322  {
323  entity item = spawn();
324  item.ok_item = true;
325  item.classname = class_name;
326  Item_InitializeLoot(item, class_name, position, spread,
328  }
329  random_items_is_spawning = false;
330 }
331 
332 //============================= Hooks ========================================
333 
334 MUTATOR_HOOKFUNCTION(random_items, BuildMutatorsString)
335 {
336  M_ARGV(0, string) = strcat(M_ARGV(0, string), ":random_items");
337 }
338 
339 MUTATOR_HOOKFUNCTION(random_items, BuildMutatorsPrettyString)
340 {
341  M_ARGV(0, string) = strcat(M_ARGV(0, string), ", Random items");
342 }
343 
345 MUTATOR_HOOKFUNCTION(random_items, FilterItem, CBC_ORDER_LAST)
346 {
347  //PrintToChatAll("FilterItem");
349  {
350  return false;
351  }
352  if (random_items_is_spawning == true)
353  {
354  return false;
355  }
356  entity item = M_ARGV(0, entity);
357  if (Item_IsLoot(item))
358  {
359  return false;
360  }
361  if (RandomItems_ReplaceMapItem(item) == NULL)
362  {
363  return false;
364  }
365  return true;
366 }
367 
369 MUTATOR_HOOKFUNCTION(random_items, ItemTouched, CBC_ORDER_LAST)
370 {
371  //PrintToChatAll("ItemTouched");
373  {
374  return;
375  }
376  entity item = M_ARGV(0, entity);
377  if (Item_IsLoot(item))
378  {
379  return;
380  }
381  entity new_item = RandomItems_ReplaceMapItem(item);
382  if (new_item == NULL)
383  {
384  return;
385  }
386  Item_ScheduleRespawn(new_item);
387  delete(item);
388 }
389 
391 MUTATOR_HOOKFUNCTION(random_items, PlayerDies)
392 {
393  //PrintToChatAll("PlayerDies");
395  {
396  return;
397  }
398  entity victim = M_ARGV(2, entity);
399  vector loot_position = victim.origin + '0 0 32';
400  int num_loot_items = floor(autocvar_g_random_loot_min + random() *
402  for (int item_index = 0; item_index < num_loot_items; ++item_index)
403  {
404  RandomItems_SpawnLootItem(loot_position);
405  }
406 }
Item is usable during normal gameplay.
Definition: item.qh:98
float autocvar_g_random_loot_time
Amount of time the loot will stay.
float autocvar_g_random_loot_max
Maximum amount of loot items.
string RandomSelection_chosen_string
Definition: random.qh:7
bool Item_IsDefinitionAllowed(entity definition)
Checks whether the items with the specified definition are allowed to spawn.
Definition: spawning.qc:55
string RandomItems_GetItemReplacementClassNames(entity item)
Returns list of classnames to replace a map item with.
void Item_Initialize(entity item, string class_name)
Initializes the item according to class name.
Definition: spawning.qc:75
ERASEABLE void RandomSelection_Init()
Definition: random.qc:4
bool Item_InitializeLoot(entity item, string class_name, vector position, vector vel, float time_to_live)
Initializes the loot item.
Definition: spawning.qc:101
float CVAR_TYPEFLAG_EXISTS
entity() spawn
bool autocvar_g_random_items
Whether to enable random items.
Header file that describes the random items mutator.
string RandomItems_GetRandomVanillaItemClassName(string prefix, int types)
Returns a random classname of the vanilla item.
#define RandomSelection_AddString(s, weight, priority)
Definition: random.qh:16
float RandomSelection_chosen_float
Definition: random.qh:6
float autocvar_g_random_loot_min
Classnames to replace s with.
#define LOG_WARNF(...)
Definition: log.qh:67
#define MUTATOR_IS_ENABLED(this)
Definition: base.qh:176
const int CBC_ORDER_LAST
Definition: base.qh:8
spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 f1 s1 strcat(_("Level %s: "), "^BG%s\3\, _("^BGPress ^F2%s^BG to enter the game"))
string RandomItems_GetRandomItemClassName(string prefix)
Returns a random classname of the item.
string RandomItems_GetRandomItemClassNameWithProperty(string prefix,.bool item_property)
Returns a random classname of the item with specific property.
void RandomItems_SpawnLootItem(vector position)
Spawns a random loot item.
#define NULL
Definition: post.qh:17
#define M_ARGV(x, type)
Definition: events.qh:17
vector(float skel, float bonenum) _skel_get_boneabs_hidden
#define tokenize_console
Definition: dpextensions.qh:24
MUTATOR_HOOKFUNCTION(random_items, BuildMutatorsString)
#define RandomSelection_AddFloat(f, weight, priority)
Definition: random.qh:15
bool autocvar_g_random_loot
Whether to enable random loot.
bool Item_ShouldKeepPosition(entity item)
Returns whether item should keep its position or be dropped to the ground.
Definition: spawning.qc:131
entity Item_Create(string class_name, vector position, bool no_align)
Creates a new item.
Definition: spawning.qc:60
#define MUTATOR_CALLHOOK(id,...)
Definition: base.qh:140
setorigin(ent, v)
bool Item_IsLoot(entity item)
Returns whether the item is loot.
Definition: spawning.qc:121
const int WEP_FLAG_MUTATORBLOCKED
Definition: weapon.qh:203
float autocvar_g_random_loot_spread
How far can loot be thrown.
entity RandomItems_ReplaceMapItem(entity item)
Replaces a map item.
bool random_items_is_spawning
Probability of random s spawning as loot.
#define FOREACH(list, cond, body)
Definition: iter.qh:19
void Item_ScheduleRespawn(entity e)
Definition: items.qc:351
entity Item_CreateLoot(string class_name, vector position, vector vel, float time_to_live)
Creates a loot item.
Definition: spawning.qc:90