Xonotic
items.qc
Go to the documentation of this file.
1 #include "items.qh"
2 
3 #include <common/constants.qh>
6 #include <common/items/_mod.qh>
16 #include <common/util.qh>
17 #include <common/weapons/_all.qh>
18 #include <common/wepent.qh>
19 #include <lib/warpzone/common.qh>
21 #include <server/bot/api.qh>
22 #include <server/command/vote.qh>
23 #include <server/damage.qh>
24 #include <server/mutators/_mod.qh>
25 #include <server/teamplay.qh>
26 #include <server/weapons/common.qh>
29 #include <server/world.qh>
30 
31 bool ItemSend(entity this, entity to, int sf)
32 {
33  if(this.gravity)
34  sf |= ISF_DROP;
35  else
36  sf &= ~ISF_DROP;
37 
38  WriteHeader(MSG_ENTITY, ENT_CLIENT_ITEM);
39  WriteByte(MSG_ENTITY, sf);
40 
41  //WriteByte(MSG_ENTITY, this.cnt);
42  if(sf & ISF_LOCATION)
43  {
44  WriteVector(MSG_ENTITY, this.origin);
45  }
46 
47  if(sf & ISF_ANGLES)
48  {
49  WriteAngleVector(MSG_ENTITY, this.angles);
50  }
51 
52  // sets size on the client, unused on server
53  //if(sf & ISF_SIZE)
54 
55  if(sf & ISF_STATUS)
56  WriteByte(MSG_ENTITY, this.ItemStatus);
57 
58  if(sf & ISF_MODEL)
59  {
60  WriteShort(MSG_ENTITY, bound(0, this.fade_end, 32767));
61  WriteShort(MSG_ENTITY, bound(0, this.fade_start, 32767));
62 
63  if(this.mdl == "")
64  LOG_TRACE("^1WARNING!^7 this.mdl is unset for item ", this.classname, "expect a crash just about now");
65 
66  WriteString(MSG_ENTITY, this.mdl);
67  WriteByte(MSG_ENTITY, bound(0, this.skin, 255));
68  }
69 
70  if(sf & ISF_COLORMAP)
71  {
72  WriteShort(MSG_ENTITY, this.colormap);
73  WriteByte(MSG_ENTITY, this.glowmod.x * 255.0);
74  WriteByte(MSG_ENTITY, this.glowmod.y * 255.0);
75  WriteByte(MSG_ENTITY, this.glowmod.z * 255.0);
76  }
77 
78  if(sf & ISF_DROP)
79  {
80  WriteVector(MSG_ENTITY, this.velocity);
81  }
82 
83  return true;
84 }
85 
86 void ItemUpdate(entity this)
87 {
88  this.oldorigin = this.origin;
89  this.SendFlags |= ISF_LOCATION;
90 }
91 
93 {
94  if(getSendEntity(this) == ItemSend)
95  ItemUpdate(this);
96 }
97 
99 {
100  if(this.itemdef.instanceOfPowerup)
101  {
102  if(autocvar_g_powerups > 0)
103  return true;
104  if(autocvar_g_powerups == 0)
105  return false;
106  }
107  else
108  {
110  return true;
111  if(autocvar_g_pickup_items == 0)
112  return false;
113  if(g_weaponarena)
114  if(STAT(WEAPONS, this) || this.itemdef.instanceOfAmmo) // no item or ammo pickups in weaponarena
115  return false;
116  }
117  return true;
118 }
119 
120 void Item_Show(entity e, int mode)
121 {
122  e.effects &= ~(EF_ADDITIVE | EF_STARDUST | EF_FULLBRIGHT | EF_NODEPTHTEST);
123  e.ItemStatus &= ~ITS_STAYWEP;
124  entity def = e.itemdef;
125  if (mode > 0)
126  {
127  // make the item look normal, and be touchable
128  e.model = e.mdl;
129  e.solid = SOLID_TRIGGER;
130  e.spawnshieldtime = 1;
131  e.ItemStatus |= ITS_AVAILABLE;
132  }
133  else if (mode < 0)
134  {
135  // hide the item completely
136  e.model = string_null;
137  e.solid = SOLID_NOT;
138  e.spawnshieldtime = 1;
139  e.ItemStatus &= ~ITS_AVAILABLE;
140  }
141  else
142  {
143  bool nostay = def.instanceOfWeaponPickup ? !!(def.m_weapon.m_wepset & WEPSET_SUPERWEAPONS) : false // no weapon-stay on superweapons
144  || e.team // weapon stay isn't supported for teamed weapons
145  ;
146  if(def.instanceOfWeaponPickup && !nostay && g_weapon_stay)
147  {
148  // make the item translucent and not touchable
149  e.model = e.mdl;
150  e.solid = SOLID_TRIGGER; // can STILL be picked up!
151  e.effects |= EF_STARDUST;
152  e.spawnshieldtime = 0; // field indicates whether picking it up may give you anything other than the weapon
153  e.ItemStatus |= (ITS_AVAILABLE | ITS_STAYWEP);
154  }
155  else
156  {
157  //setmodel(e, "null");
158  e.solid = SOLID_NOT;
159  e.colormod = '0 0 0';
160  //e.glowmod = e.colormod;
161  e.spawnshieldtime = 1;
162  e.ItemStatus &= ~ITS_AVAILABLE;
163  }
164  }
165 
166  if (def.m_glow)
167  e.ItemStatus |= ITS_GLOW;
168 
170  e.effects |= EF_NODEPTHTEST;
171 
173  e.ItemStatus |= ITS_ALLOWFB;
174  else
175  e.ItemStatus &= ~ITS_ALLOWFB;
176 
178  e.ItemStatus |= ITS_ALLOWSI;
179 
180  // relink entity (because solid may have changed)
181  setorigin(e, e.origin);
182  e.SendFlags |= ISF_STATUS;
183 }
184 
185 void Item_Think(entity this)
186 {
187  this.nextthink = time;
188  if(this.origin != this.oldorigin)
189  ItemUpdate(this);
190 }
191 
194 float Item_ItemsTime_UpdateTime(entity e, float t);
195 void Item_ItemsTime_SetTime(entity e, float t);
197 
199 {
200  Item_Show(this, 1);
201  sound(this, CH_TRIGGER, this.itemdef.m_respawnsound, VOL_BASE, ATTEN_NORM); // play respawn sound
202  setorigin(this, this.origin);
203 
204  if (Item_ItemsTime_Allow(this.itemdef) || (STAT(WEAPONS, this) & WEPSET_SUPERWEAPONS))
205  {
206  float t = Item_ItemsTime_UpdateTime(this, 0);
207  Item_ItemsTime_SetTime(this, t);
209  }
210 
211  setthink(this, Item_Think);
212  this.nextthink = time;
213 
214  //Send_Effect(EFFECT_ITEM_RESPAWN, this.origin + this.mins_z * '0 0 1' + '0 0 48', '0 0 0', 1);
215  Send_Effect(EFFECT_ITEM_RESPAWN, CENTER_OR_VIEWOFS(this), '0 0 0', 1);
216 }
217 
219 {
221  {
222  if(this.waypointsprite_attached)
223  WaypointSprite_Kill(this.waypointsprite_attached);
224  Item_Respawn(this);
225  }
226  else
227  {
228  this.nextthink = time + 1;
229  this.item_respawncounter += 1;
230  if(this.item_respawncounter == 1)
231  {
232  do {
233  {
234  entity wi = REGISTRY_GET(Weapons, this.weapon);
235  if (wi != WEP_Null) {
236  entity wp = WaypointSprite_Spawn(WP_Weapon, 0, 0, this, '0 0 64', NULL, 0, this, waypointsprite_attached, true, RADARICON_Weapon);
237  wp.wp_extra = wi.m_id;
238  break;
239  }
240  }
241  {
242  entity ii = this.itemdef;
243  if (ii != NULL) {
244  entity wp = WaypointSprite_Spawn(WP_Item, 0, 0, this, '0 0 64', NULL, 0, this, waypointsprite_attached, true, RADARICON_Item);
245  wp.wp_extra = ii.m_id;
246  break;
247  }
248  }
249  } while (0);
250  bool mutator_returnvalue = MUTATOR_CALLHOOK(Item_RespawnCountdown, this);
251  if(this.waypointsprite_attached)
252  {
253  GameItem def = this.itemdef;
254  if (Item_ItemsTime_SpectatorOnly(def) && !mutator_returnvalue)
255  WaypointSprite_UpdateRule(this.waypointsprite_attached, 0, SPRITERULE_SPECTATOR);
256  WaypointSprite_UpdateBuildFinished(this.waypointsprite_attached, time + ITEM_RESPAWN_TICKS);
257  }
258  }
259 
260  if(this.waypointsprite_attached)
261  {
263  if(this.waypointsprite_attached.waypointsprite_visible_for_player(this.waypointsprite_attached, it, it))
264  {
265  msg_entity = it;
266  soundto(MSG_ONE, this, CH_TRIGGER, SND(ITEMRESPAWNCOUNTDOWN), VOL_BASE, ATTEN_NORM, 0); // play respawn sound
267  }
268  });
269 
270  WaypointSprite_Ping(this.waypointsprite_attached);
271  //WaypointSprite_UpdateHealth(this.waypointsprite_attached, this.item_respawncounter);
272  }
273  }
274 }
275 
277 {
278  this.nextthink = time;
279  if(this.origin != this.oldorigin)
280  ItemUpdate(this);
281 
282  if(time >= this.wait)
283  Item_Respawn(this);
284 }
285 
287 {
288  // if the respawn time is longer than 10 seconds, show a waypoint, otherwise, just respawn normally
289  if ((Item_ItemsTime_Allow(e.itemdef) || (STAT(WEAPONS, e) & WEPSET_SUPERWEAPONS) || MUTATOR_CALLHOOK(Item_ScheduleRespawn, e, t)) && (t - ITEM_RESPAWN_TICKS) > 0)
290  {
292  e.nextthink = time + max(0, t - ITEM_RESPAWN_TICKS);
293  e.scheduledrespawntime = e.nextthink + ITEM_RESPAWN_TICKS;
294  e.item_respawncounter = 0;
295  if(Item_ItemsTime_Allow(e.itemdef) || (STAT(WEAPONS, e) & WEPSET_SUPERWEAPONS))
296  {
297  t = Item_ItemsTime_UpdateTime(e, e.scheduledrespawntime);
300  }
301  }
302  else
303  {
305  e.nextthink = time;
306  e.scheduledrespawntime = time + t;
307  e.wait = time + t;
308 
309  if(Item_ItemsTime_Allow(e.itemdef) || (STAT(WEAPONS, e) & WEPSET_SUPERWEAPONS))
310  {
311  t = Item_ItemsTime_UpdateTime(e, e.scheduledrespawntime);
314  }
315  }
316 }
317 
318 AUTOCVAR(g_pickup_respawntime_scaling_reciprocal, float, 0.0, "Multiply respawn time by `reciprocal / (p + offset) + linear` where `p` is the current number of players, takes effect with 2 or more players present, `reciprocal` (with `offset` and `linear` set to 0) can be used to achieve a constant number of items spawned *per player*");
319 AUTOCVAR(g_pickup_respawntime_scaling_offset, float, 0.0, "Multiply respawn time by `reciprocal / (p + offset) + linear` where `p` is the current number of players, takes effect with 2 or more players present, `offset` offsets the curve left or right - the results are not intuitive and I recommend plotting the respawn time and the number of items per player to see what's happening");
320 AUTOCVAR(g_pickup_respawntime_scaling_linear, float, 1.0, "Multiply respawn time by `reciprocal / (p + offset) + linear` where `p` is the current number of players, takes effect with 2 or more players present, `linear` can be used to simply scale the respawn time linearly");
321 
323 float adjust_respawntime(float normal_respawntime) {
324  float r = autocvar_g_pickup_respawntime_scaling_reciprocal;
325  float o = autocvar_g_pickup_respawntime_scaling_offset;
326  float l = autocvar_g_pickup_respawntime_scaling_linear;
327 
328  if (r == 0 && l == 1) {
329  return normal_respawntime;
330  }
331 
334  int players = 0;
335  for (int i = 1; i <= NUM_TEAMS; ++i)
336  {
337  if (TeamBalance_IsTeamAllowed(balance, i))
338  {
339  players += TeamBalance_GetNumberOfPlayers(balance, i);
340  }
341  }
342  TeamBalance_Destroy(balance);
343 
344  if (players >= 2) {
345  return normal_respawntime * (r / (players + o) + l);
346  } else {
347  return normal_respawntime;
348  }
349 }
350 
352 {
353  if(e.respawntime > 0)
354  {
355  Item_Show(e, 0);
356 
357  float adjusted_respawntime = adjust_respawntime(e.respawntime);
358  //LOG_INFOF("item %s will respawn in %f", e.classname, adjusted_respawntime);
359 
360  // range: adjusted_respawntime - respawntimejitter .. adjusted_respawntime + respawntimejitter
361  float respawn_in = adjusted_respawntime + crandom() * e.respawntimejitter;
362  Item_ScheduleRespawnIn(e, respawn_in);
363  }
364  else // if respawntime is -1, this item does not respawn
365  Item_Show(e, -1);
366 }
367 
368 AUTOCVAR(g_pickup_respawntime_initial_random, int, 1,
369  "For items that don't start spawned: 0: spawn after their normal respawntime; 1: spawn after `random * respawntime` with the *same* random; 2: same as 1 but each item has separate random");
370 
372 {
373  Item_Show(e, 0);
374 
375  float spawn_in;
376  if (autocvar_g_pickup_respawntime_initial_random == 0)
377  {
378  // range: respawntime .. respawntime + respawntimejitter
379  spawn_in = e.respawntime + random() * e.respawntimejitter;
380  }
381  else
382  {
383  float rnd;
384  if (autocvar_g_pickup_respawntime_initial_random == 1)
385  {
386  static float shared_random = 0;
387  // NOTE this code works only if items are scheduled at the same time (normal case)
388  // NOTE2 random() can't return exactly 1 so this check always work as intended
389  if (!shared_random || floor(time) > shared_random)
390  shared_random = floor(time) + random();
391  rnd = shared_random - floor(time);
392  }
393  else
394  rnd = random();
395 
396  // range:
397  // if respawntime >= ITEM_RESPAWN_TICKS: ITEM_RESPAWN_TICKS .. respawntime + respawntimejitter
398  // else: 0 .. ITEM_RESPAWN_TICKS
399  // this is to prevent powerups spawning unexpectedly without waypoints
400  spawn_in = ITEM_RESPAWN_TICKS + rnd * (e.respawntime + e.respawntimejitter - ITEM_RESPAWN_TICKS);
401  }
402 
403  Item_ScheduleRespawnIn(e, max(0, game_starttime - time) + ((e.respawntimestart) ? e.respawntimestart : spawn_in));
404 }
405 
406 void GiveRandomWeapons(entity receiver, int num_weapons, string weapon_names,
407  entity ammo_entity)
408 {
409  if (num_weapons == 0)
410  {
411  return;
412  }
413  int num_potential_weapons = tokenize_console(weapon_names);
414  for (int give_attempt = 0; give_attempt < num_weapons; ++give_attempt)
415  {
417  for (int weapon_index = 0; weapon_index < num_potential_weapons;
418  ++weapon_index)
419  {
420  string weapon = argv(weapon_index);
421  FOREACH(Weapons, it != WEP_Null,
422  {
423  // Finding a weapon which player doesn't have.
424  if (!(STAT(WEAPONS, receiver) & it.m_wepset) && (it.netname == weapon))
425  {
426  RandomSelection_AddEnt(it, 1, 1);
427  break;
428  }
429  });
430  }
432  {
433  return;
434  }
435  STAT(WEAPONS, receiver) |= RandomSelection_chosen_ent.m_wepset;
436  if (RandomSelection_chosen_ent.ammo_type == RES_NONE)
437  {
438  continue;
439  }
440  if (GetResource(receiver,
441  RandomSelection_chosen_ent.ammo_type) != 0)
442  {
443  continue;
444  }
445  GiveResource(receiver, RandomSelection_chosen_ent.ammo_type,
446  GetResource(ammo_entity,
447  RandomSelection_chosen_ent.ammo_type));
448  }
449 }
450 
451 bool Item_GiveAmmoTo(entity item, entity player, Resource res_type, float ammomax)
452 {
453  float amount = GetResource(item, res_type);
454  if (amount == 0)
455  {
456  return false;
457  }
458  float player_amount = GetResource(player, res_type);
459  if (item.spawnshieldtime)
460  {
461  if ((player_amount >= ammomax) && (item.pickup_anyway <= 0))
462  return false;
463  }
464  else if (g_weapon_stay == 2)
465  {
466  ammomax = min(amount, ammomax);
467  if(player_amount >= ammomax)
468  return false;
469  }
470  else
471  return false;
472  if (amount < 0)
473  TakeResourceWithLimit(player, res_type, -amount, ammomax);
474  else
475  GiveResourceWithLimit(player, res_type, amount, ammomax);
476  return true;
477 }
478 
479 bool Item_GiveTo(entity item, entity player)
480 {
481  // if nothing happens to player, just return without taking the item
482  int _switchweapon = 0;
483  // in case the player has autoswitch enabled do the following:
484  // if the player is using their best weapon before items are given, they
485  // probably want to switch to an even better weapon after items are given
486 
487  if(CS_CVAR(player).cvar_cl_autoswitch)
488  {
489  for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
490  {
491  .entity weaponentity = weaponentities[slot];
492  if(player.(weaponentity).m_weapon != WEP_Null || slot == 0)
493  {
494  if(player.(weaponentity).m_switchweapon == w_getbestweapon(player, weaponentity))
495  _switchweapon |= BIT(slot);
496 
497  if(!(STAT(WEAPONS, player) & WepSet_FromWeapon(player.(weaponentity).m_switchweapon)))
498  _switchweapon |= BIT(slot);
499  }
500  }
501  }
502  bool pickedup = false;
503  pickedup |= Item_GiveAmmoTo(item, player, RES_HEALTH, item.max_health);
504  pickedup |= Item_GiveAmmoTo(item, player, RES_ARMOR, item.max_armorvalue);
505  pickedup |= Item_GiveAmmoTo(item, player, RES_SHELLS, g_pickup_shells_max);
506  pickedup |= Item_GiveAmmoTo(item, player, RES_BULLETS, g_pickup_nails_max);
507  pickedup |= Item_GiveAmmoTo(item, player, RES_ROCKETS, g_pickup_rockets_max);
508  pickedup |= Item_GiveAmmoTo(item, player, RES_CELLS, g_pickup_cells_max);
509  pickedup |= Item_GiveAmmoTo(item, player, RES_PLASMA, g_pickup_plasma_max);
510  pickedup |= Item_GiveAmmoTo(item, player, RES_FUEL, g_pickup_fuel_max);
511  if (item.itemdef.instanceOfWeaponPickup)
512  {
513  WepSet w;
514  w = STAT(WEAPONS, item);
515  w &= ~STAT(WEAPONS, player);
516 
517  if (w || (item.spawnshieldtime && item.pickup_anyway > 0))
518  {
519  pickedup = true;
520  FOREACH(Weapons, it != WEP_Null, {
521  if(w & (it.m_wepset))
522  {
523  for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
524  {
525  .entity weaponentity = weaponentities[slot];
526  if(player.(weaponentity).m_weapon != WEP_Null || slot == 0)
527  W_DropEvent(wr_pickup, player, it.m_id, item, weaponentity);
528  }
529  W_GiveWeapon(player, it.m_id);
530  }
531  });
532  }
533  }
534 
535  if (item.itemdef.instanceOfPowerup)
536  {
537  if ((item.itemdef == ITEM_JetpackRegen) && !(player.items & IT_FUEL_REGEN))
538  Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_ITEM_FUELREGEN_GOT);
539  else if ((item.itemdef == ITEM_Jetpack) && !(player.items & IT_JETPACK))
540  Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_ITEM_JETPACK_GOT);
541  }
542 
543  int its;
544  if((its = (item.items - (item.items & player.items)) & IT_PICKUPMASK))
545  {
546  pickedup = true;
547  player.items |= its;
548  // TODO: we probably want to show a message in the console, but not this one!
549  //Send_Notification(NOTIF_ONE, player, MSG_INFO, INFO_ITEM_WEAPON_GOT, item.netname);
550  }
551 
552  if (item.strength_finished)
553  {
554  pickedup = true;
555  float t = max(StatusEffects_gettime(STATUSEFFECT_Strength, player), time);
557  t += item.strength_finished;
558  else
559  t = max(t, time + item.strength_finished);
560  StatusEffects_apply(STATUSEFFECT_Strength, player, t, 0);
561  }
562  if (item.invincible_finished)
563  {
564  pickedup = true;
565  float t = max(StatusEffects_gettime(STATUSEFFECT_Shield, player), time);
567  t += item.invincible_finished;
568  else
569  t = max(t, time + item.invincible_finished);
570  StatusEffects_apply(STATUSEFFECT_Shield, player, t, 0);
571  }
572  if (item.speed_finished)
573  {
574  pickedup = true;
575  float t = max(StatusEffects_gettime(STATUSEFFECT_Speed, player), time);
577  t += item.speed_finished;
578  else
579  t = max(t, time + item.speed_finished);
580  StatusEffects_apply(STATUSEFFECT_Speed, player, t, 0);
581  }
582  if (item.invisibility_finished)
583  {
584  pickedup = true;
585  float t = max(StatusEffects_gettime(STATUSEFFECT_Invisibility, player), time);
587  t += item.invisibility_finished;
588  else
589  t = max(t, time + item.invisibility_finished);
590  StatusEffects_apply(STATUSEFFECT_Invisibility, player, t, 0);
591  }
592  if (item.superweapons_finished)
593  {
594  pickedup = true;
595  StatusEffects_apply(STATUSEFFECT_Superweapons, player, max(StatusEffects_gettime(STATUSEFFECT_Superweapons, player), time) + item.superweapons_finished, 0);
596  }
597 
598  // always eat teamed entities
599  if(item.team)
600  pickedup = true;
601 
602  if (!pickedup)
603  return false;
604 
605  // crude hack to enforce switching weapons
606  if(g_cts && item.itemdef.instanceOfWeaponPickup && !CS_CVAR(player).cvar_cl_cts_noautoswitch)
607  {
608  for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
609  {
610  .entity weaponentity = weaponentities[slot];
611  if(player.(weaponentity).m_weapon != WEP_Null || slot == 0)
612  W_SwitchWeapon_Force(player, REGISTRY_GET(Weapons, item.weapon), weaponentity);
613  }
614  return true;
615  }
616 
617  if(_switchweapon)
618  {
619  for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
620  {
621  .entity weaponentity = weaponentities[slot];
622  if(_switchweapon & BIT(slot))
623  if(player.(weaponentity).m_switchweapon != w_getbestweapon(player, weaponentity))
624  W_SwitchWeapon_Force(player, w_getbestweapon(player, weaponentity), weaponentity);
625  }
626  }
627 
628  return true;
629 }
630 
631 void Item_Touch(entity this, entity toucher)
632 {
633  // remove the item if it's currnetly in a NODROP brush or hits a NOIMPACT surface (such as sky)
634  if (Item_IsLoot(this))
635  {
636  if (ITEM_TOUCH_NEEDKILL())
637  {
638  delete(this);
639  return;
640  }
641  }
642 
643  if(!(toucher.flags & FL_PICKUPITEMS)
644  || STAT(FROZEN, toucher)
645  || IS_DEAD(toucher)
646  || (this.solid != SOLID_TRIGGER)
647  || (this.owner == toucher)
648  || (time < this.item_spawnshieldtime)
649  ) { return; }
650 
651  switch (MUTATOR_CALLHOOK(ItemTouch, this, toucher))
652  {
653  case MUT_ITEMTOUCH_RETURN: { return; }
654  case MUT_ITEMTOUCH_PICKUP: { toucher = M_ARGV(1, entity); goto pickup; }
655  }
656 
657  toucher = M_ARGV(1, entity);
658 
659  if (Item_IsExpiring(this))
660  {
661  this.strength_finished = max(0, this.strength_finished - time);
662  this.invincible_finished = max(0, this.invincible_finished - time);
663  this.speed_finished = max(0, this.speed_finished - time);
664  this.invisibility_finished = max(0, this.invisibility_finished - time);
666  }
667  bool gave = ITEM_HANDLE(Pickup, this.itemdef, this, toucher);
668  if (!gave)
669  {
670  if (Item_IsExpiring(this))
671  {
672  // undo what we did above
673  this.strength_finished += time;
674  this.invincible_finished += time;
675  this.speed_finished += time;
676  this.invisibility_finished += time;
677  this.superweapons_finished += time;
678  }
679  return;
680  }
681 
682 LABEL(pickup)
683 
684  if(this.target && this.target != "" && this.target != "###item###") // defrag support
685  SUB_UseTargets(this, toucher, NULL);
686 
687  STAT(LAST_PICKUP, toucher) = time;
688 
689  Send_Effect(EFFECT_ITEM_PICKUP, CENTER_OR_VIEWOFS(this), '0 0 0', 1);
690  _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);
691 
692  MUTATOR_CALLHOOK(ItemTouched, this, toucher);
693  if (wasfreed(this))
694  {
695  return;
696  }
697 
698  if (Item_IsLoot(this))
699  {
700  delete(this);
701  return;
702  }
703  if (!this.spawnshieldtime)
704  {
705  return;
706  }
707  entity e;
708  if (this.team)
709  {
711  IL_EACH(g_items, it.team == this.team,
712  {
713  if (it.itemdef) // is a registered item
714  {
715  Item_Show(it, -1);
716  it.scheduledrespawntime = 0;
717  RandomSelection_AddEnt(it, it.cnt, 0);
718  }
719  });
721  Item_Show(e, 1); // reset its state so it is visible (extra sendflags doesn't matter, this happens anyway)
722  }
723  else
724  e = this;
726 }
727 
728 void Item_Reset(entity this)
729 {
730  Item_Show(this, !this.state);
731  setorigin(this, this.origin);
732 
733  if (Item_IsLoot(this))
734  {
735  return;
736  }
737  setthink(this, Item_Think);
738  this.nextthink = time;
739  if (this.waypointsprite_attached)
740  {
741  WaypointSprite_Kill(this.waypointsprite_attached);
742  }
743  if (this.itemdef.instanceOfPowerup || (STAT(WEAPONS, this) & WEPSET_SUPERWEAPONS)) // do not spawn powerups initially!
744  {
746  }
747 }
748 
750 {
751  entity e;
752 
753  if(this.effects & EF_NODRAW)
754  {
755  // marker for item team search
756  LOG_TRACE("Initializing item team ", ftos(this.team));
758  IL_EACH(g_items, it.team == this.team,
759  {
760  if(it.itemdef) // is a registered item
761  RandomSelection_AddEnt(it, it.cnt, 0);
762  });
763 
765  if (!e)
766  return;
767 
768  IL_EACH(g_items, it.team == this.team,
769  {
770  if(it.itemdef) // is a registered item
771  {
772  if(it != e)
773  {
774  // make it non-spawned
775  Item_Show(it, -1);
776  it.state = 1; // state 1 = initially hidden item, apparently
777  }
778  else
779  Item_Reset(it);
780  it.effects &= ~EF_NODRAW;
781  }
782  });
783  }
784 }
785 
786 // Savage: used for item garbage-collection
787 void RemoveItem(entity this)
788 {
789  if(wasfreed(this) || !this) { return; }
790  Send_Effect(EFFECT_ITEM_PICKUP, CENTER_OR_VIEWOFS(this), '0 0 0', 1);
791  delete(this);
792 }
793 
794 // pickup evaluation functions
795 // these functions decide how desirable an item is to the bots
796 
797 float generic_pickupevalfunc(entity player, entity item) {return item.bot_pickupbasevalue;}
798 
800 {
801  // See if I have it already
802  if(STAT(WEAPONS, player) & STAT(WEAPONS, item))
803  {
804  // If I can pick it up
805  if(!item.spawnshieldtime)
806  return 0;
807  return ammo_pickupevalfunc(player, item);
808  }
809 
810  // reduce weapon value if bot already got a good arsenal
811  float c = 1;
812  int weapons_value = 0;
813  FOREACH(Weapons, it != WEP_Null && (STAT(WEAPONS, player) & it.m_wepset), {
814  weapons_value += it.bot_pickupbasevalue;
815  });
816  c -= bound(0, weapons_value / 20000, 1) * 0.5;
817 
818  return item.bot_pickupbasevalue * c;
819 }
820 
821 float ammo_pickupevalfunc(entity player, entity item)
822 {
823  bool need_shells = false, need_nails = false, need_rockets = false, need_cells = false, need_plasma = false, need_fuel = false;
824  entity wpn = NULL;
825  float c = 0;
826  float rating = 0;
827 
828  // Detect needed ammo
829  if(item.itemdef.instanceOfWeaponPickup)
830  {
831  entity ammo = NULL;
832  if(GetResource(item, RES_SHELLS)) { need_shells = true; ammo = ITEM_Shells; }
833  else if(GetResource(item, RES_BULLETS)) { need_nails = true; ammo = ITEM_Bullets; }
834  else if(GetResource(item, RES_ROCKETS)) { need_rockets = true; ammo = ITEM_Rockets; }
835  else if(GetResource(item, RES_CELLS)) { need_cells = true; ammo = ITEM_Cells; }
836  else if(GetResource(item, RES_PLASMA)) { need_plasma = true; ammo = ITEM_Plasma; }
837  else if(GetResource(item, RES_FUEL)) { need_fuel = true; ammo = ITEM_JetpackFuel; }
838 
839  if(!ammo)
840  return 0;
841  wpn = item;
842  rating = ammo.m_botvalue;
843  }
844  else
845  {
846  FOREACH(Weapons, it != WEP_Null, {
847  if(!(STAT(WEAPONS, player) & (it.m_wepset)))
848  continue;
849 
850  switch(it.ammo_type)
851  {
852  case RES_SHELLS: need_shells = true; break;
853  case RES_BULLETS: need_nails = true; break;
854  case RES_ROCKETS: need_rockets = true; break;
855  case RES_CELLS: need_cells = true; break;
856  case RES_PLASMA: need_plasma = true; break;
857  case RES_FUEL: need_fuel = true; break;
858  }
859  });
860  rating = item.bot_pickupbasevalue;
861  }
862 
863  float noammorating = 0.5;
864 
865  if ((need_shells) && GetResource(item, RES_SHELLS) && (GetResource(player, RES_SHELLS) < g_pickup_shells_max))
866  c = GetResource(item, RES_SHELLS) / max(noammorating, GetResource(player, RES_SHELLS));
867 
868  if ((need_nails) && GetResource(item, RES_BULLETS) && (GetResource(player, RES_BULLETS) < g_pickup_nails_max))
869  c = GetResource(item, RES_BULLETS) / max(noammorating, GetResource(player, RES_BULLETS));
870 
871  if ((need_rockets) && GetResource(item, RES_ROCKETS) && (GetResource(player, RES_ROCKETS) < g_pickup_rockets_max))
872  c = GetResource(item, RES_ROCKETS) / max(noammorating, GetResource(player, RES_ROCKETS));
873 
874  if ((need_cells) && GetResource(item, RES_CELLS) && (GetResource(player, RES_CELLS) < g_pickup_cells_max))
875  c = GetResource(item, RES_CELLS) / max(noammorating, GetResource(player, RES_CELLS));
876 
877  if ((need_plasma) && GetResource(item, RES_PLASMA) && (GetResource(player, RES_PLASMA) < g_pickup_plasma_max))
878  c = GetResource(item, RES_PLASMA) / max(noammorating, GetResource(player, RES_PLASMA));
879 
880  if ((need_fuel) && GetResource(item, RES_FUEL) && (GetResource(player, RES_FUEL) < g_pickup_fuel_max))
881  c = GetResource(item, RES_FUEL) / max(noammorating, GetResource(player, RES_FUEL));
882 
883  rating *= min(c, 2);
884  if(wpn)
885  rating += wpn.bot_pickupbasevalue * 0.1;
886  return rating;
887 }
888 
890 {
891  float c = 0;
892  float rating = item.bot_pickupbasevalue;
893 
894  float itemarmor = GetResource(item, RES_ARMOR);
895  float itemhealth = GetResource(item, RES_HEALTH);
896 
897  if(item.item_group)
898  {
899  itemarmor *= min(4, item.item_group_count);
900  itemhealth *= min(4, item.item_group_count);
901  }
902 
903  if (itemarmor && (GetResource(player, RES_ARMOR) < item.max_armorvalue))
904  c = itemarmor / max(1, GetResource(player, RES_ARMOR) * 2/3 + GetResource(player, RES_HEALTH) * 1/3);
905 
906  if (itemhealth && (GetResource(player, RES_HEALTH) < item.max_health))
907  c = itemhealth / max(1, GetResource(player, RES_HEALTH));
908 
909  rating *= min(2, c);
910  return rating;
911 }
912 
913 void Item_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force)
914 {
915  if(ITEM_DAMAGE_NEEDKILL(deathtype))
916  RemoveItem(this);
917 }
918 
919 void item_use(entity this, entity actor, entity trigger)
920 {
921  // use the touch function to handle collection
922  gettouch(this)(this, actor);
923 }
924 
925 void _StartItem(entity this, entity def, float defaultrespawntime, float defaultrespawntimejitter)
926 {
927  string itemname = def.m_name;
928  Model itemmodel = def.m_model;
929  Sound pickupsound = def.m_sound;
930  float(entity player, entity item) pickupevalfunc = def.m_pickupevalfunc;
931  float pickupbasevalue = def.m_botvalue;
932  int itemflags = def.m_itemflags;
933 
934  startitem_failed = false;
935 
936  this.item_model_ent = itemmodel;
937  this.item_pickupsound_ent = pickupsound;
938 
939  if(def.m_iteminit)
940  def.m_iteminit(def, this);
941 
942  if(!this.respawntime) // both need to be set
943  {
944  this.respawntime = defaultrespawntime;
945  this.respawntimejitter = defaultrespawntimejitter;
946  }
947 
948  if(!this.pickup_anyway && def.m_pickupanyway)
949  this.pickup_anyway = def.m_pickupanyway();
950 
951  int itemid = def.m_itemid;
952  this.items = itemid;
953  int weaponid = def.instanceOfWeaponPickup ? def.m_weapon.m_id : 0;
954  this.weapon = weaponid;
955 
956  if(!this.fade_end)
957  {
960  }
961 
962  if(weaponid)
963  STAT(WEAPONS, this) = WepSet_FromWeapon(REGISTRY_GET(Weapons, weaponid));
964 
965  this.flags = FL_ITEM | itemflags;
966  IL_PUSH(g_items, this);
967 
968  if(MUTATOR_CALLHOOK(FilterItem, this)) // error means we do not want the item
969  {
970  startitem_failed = true;
971  delete(this);
972  return;
973  }
974 
975  precache_model(this.model);
977 
978  if (Item_IsLoot(this))
979  {
980  this.reset = SUB_Remove;
982 
983  // Savage: remove thrown items after a certain period of time ("garbage collection")
984  setthink(this, RemoveItem);
986 
987  this.takedamage = DAMAGE_YES;
988  this.event_damage = Item_Damage;
989  // enable this to have thrown items burn in lava
990  //this.damagedbycontents = true;
991  //IL_PUSH(g_damagedbycontents, this);
992 
993  if (Item_IsExpiring(this))
994  {
995  // if item is worthless after a timer, have it expire then
996  this.nextthink = max(this.strength_finished, this.invincible_finished, this.superweapons_finished);
997  }
998 
999  // don't drop if in a NODROP zone (such as lava)
1000  traceline(this.origin, this.origin, MOVE_NORMAL, this);
1002  {
1003  startitem_failed = true;
1004  delete(this);
1005  return;
1006  }
1007  }
1008  else
1009  {
1010  if(!have_pickup_item(this))
1011  {
1012  startitem_failed = true;
1013  delete(this);
1014  return;
1015  }
1016 
1017  if(this.angles != '0 0 0')
1018  this.SendFlags |= ISF_ANGLES;
1019 
1020  this.reset = Item_Reset;
1021  // it's a level item
1022  if(this.spawnflags & 1)
1023  this.noalign = 1;
1024  if (this.noalign > 0)
1025  set_movetype(this, MOVETYPE_NONE);
1026  else
1027  set_movetype(this, MOVETYPE_TOSS);
1028  // do item filtering according to game mode and other things
1029  if (this.noalign <= 0)
1030  {
1031  // first nudge it off the floor a little bit to avoid math errors
1032  setorigin(this, this.origin + '0 0 1');
1033  // set item size before we spawn a spawnfunc_waypoint
1034  setsize(this, def.m_mins, def.m_maxs);
1035  this.SendFlags |= ISF_SIZE;
1036  // note droptofloor returns false if stuck/or would fall too far
1037  if (!this.noalign)
1038  droptofloor(this);
1039  waypoint_spawnforitem(this);
1040  }
1041 
1042  /*
1043  * can't do it that way, as it would break maps
1044  * TODO make a target_give like entity another way, that perhaps has
1045  * the weapon name in a key
1046  if(this.targetname)
1047  {
1048  // target_give not yet supported; maybe later
1049  print("removed targeted ", this.classname, "\n");
1050  startitem_failed = true;
1051  delete(this);
1052  return;
1053  }
1054  */
1055 
1056  if(this.targetname != "" && (this.spawnflags & 16))
1057  this.use = item_use;
1058 
1059  if(autocvar_spawn_debug >= 2)
1060  {
1061  // why not flags & fl_item?
1062  FOREACH_ENTITY_RADIUS(this.origin, 3, it.is_item, {
1063  LOG_TRACE("XXX Found duplicated item: ", itemname, vtos(this.origin));
1064  LOG_TRACE(" vs ", it.netname, vtos(it.origin));
1065  error("Mapper sucks.");
1066  });
1067  this.is_item = true;
1068  }
1069 
1070  weaponsInMap |= WepSet_FromWeapon(REGISTRY_GET(Weapons, weaponid));
1071 
1072  if ( def.instanceOfPowerup
1073  || def.instanceOfWeaponPickup
1074  || (def.instanceOfHealth && def != ITEM_HealthSmall)
1075  || (def.instanceOfArmor && def != ITEM_ArmorSmall)
1076  || (itemid & (IT_KEY1 | IT_KEY2))
1077  )
1078  {
1079  if(!this.target || this.target == "")
1080  this.target = "###item###"; // for finding the nearest item using findnearest
1081  }
1082 
1083  Item_ItemsTime_SetTime(this, 0);
1084  }
1085 
1086  this.bot_pickup = true;
1087  this.bot_pickupevalfunc = pickupevalfunc;
1088  this.bot_pickupbasevalue = pickupbasevalue;
1089  this.mdl = this.model ? this.model : strzone(this.item_model_ent.model_str());
1090  this.netname = itemname;
1091  settouch(this, Item_Touch);
1092  setmodel(this, MDL_Null); // precision set below
1093  //this.effects |= EF_LOWPRECISION;
1094 
1095  // support skinned models for powerups
1096  this.skin = def.m_skin;
1097  this.glowmod = def.m_color;
1098 
1099  setsize (this, this.pos1 = def.m_mins, this.pos2 = def.m_maxs);
1100 
1101  this.SendFlags |= ISF_SIZE;
1102 
1103  if (!(this.spawnflags & 1024)) {
1104  if(def.instanceOfPowerup)
1105  this.ItemStatus |= ITS_ANIMATE1;
1106 
1107  if(GetResource(this, RES_ARMOR) || GetResource(this, RES_HEALTH))
1108  this.ItemStatus |= ITS_ANIMATE2;
1109  }
1110 
1111  if(Item_IsLoot(this))
1112  this.gravity = 1;
1113 
1114  if(def.instanceOfWeaponPickup)
1115  {
1116  if (!Item_IsLoot(this)) // if dropped, colormap is already set up nicely
1117  this.colormap = 1024; // color shirt=0 pants=0 grey
1118  if (!(this.spawnflags & 1024))
1119  this.ItemStatus |= ITS_ANIMATE1;
1120  this.SendFlags |= ISF_COLORMAP;
1121  }
1122 
1123  this.state = 0;
1124  if(this.team)
1125  {
1126  if(!this.cnt)
1127  this.cnt = 1; // item probability weight
1128 
1129  this.effects |= EF_NODRAW; // marker for item team search
1130  InitializeEntity(this, Item_FindTeam, INITPRIO_FINDTARGET);
1131  }
1132  else
1133  Item_Reset(this);
1134 
1135  Net_LinkEntity(this, !(def.instanceOfPowerup || def.instanceOfHealth || def.instanceOfArmor), 0, ItemSend);
1136 
1137  // call this hook after everything else has been done
1138  if (MUTATOR_CALLHOOK(Item_Spawn, this))
1139  {
1140  startitem_failed = true;
1141  delete(this);
1142  return;
1143  }
1144 
1145  setItemGroup(this);
1146 }
1147 
1148 void StartItem(entity this, GameItem def)
1149 {
1150  def = def.m_spawnfunc_hookreplace(def, this);
1151 
1152  if (def.spawnflags & ITEM_FLAG_MUTATORBLOCKED)
1153  {
1154  delete(this);
1155  return;
1156  }
1157 
1158  this.classname = def.m_canonical_spawnfunc;
1159 
1160  _StartItem(
1161  this,
1162  this.itemdef = def,
1163  def.m_respawntime(), // defaultrespawntime
1164  def.m_respawntimejitter() // defaultrespawntimejitter
1165  );
1166 }
1167 
1168 #define IS_SMALL(def) ((def.instanceOfHealth && def == ITEM_HealthSmall) || (def.instanceOfArmor && def == ITEM_ArmorSmall))
1169 int group_count = 1;
1170 
1172 {
1173  if(!IS_SMALL(this.itemdef) || Item_IsLoot(this))
1174  return;
1175 
1176  FOREACH_ENTITY_RADIUS(this.origin, 120, (it != this) && IS_SMALL(it.itemdef),
1177  {
1178  if(!this.item_group)
1179  {
1180  if(!it.item_group)
1181  {
1182  it.item_group = group_count;
1183  group_count++;
1184  }
1185  this.item_group = it.item_group;
1186  }
1187  else // spawning item is already part of a item_group X
1188  {
1189  if(!it.item_group)
1190  it.item_group = this.item_group;
1191  else if(it.item_group != this.item_group) // found an item near the spawning item that is part of a different item_group Y
1192  {
1193  int grY = it.item_group;
1194  // move all items of item_group Y to item_group X
1195  IL_EACH(g_items, IS_SMALL(it.itemdef),
1196  {
1197  if(it.item_group == grY)
1198  it.item_group = this.item_group;
1199  });
1200  }
1201  }
1202  });
1203 }
1204 
1206 {
1207  for (int k = 1; k <= group_count; k++)
1208  {
1209  int count = 0;
1210  IL_EACH(g_items, IS_SMALL(it.itemdef) && it.item_group == k, { count++; });
1211  if (count)
1212  IL_EACH(g_items, IS_SMALL(it.itemdef) && it.item_group == k, { it.item_group_count = count; });
1213  }
1214 }
1215 
1216 void target_items_use(entity this, entity actor, entity trigger)
1217 {
1218  if(Item_IsLoot(actor))
1219  {
1220  EXACTTRIGGER_TOUCH(this, trigger);
1221  delete(actor);
1222  return;
1223  }
1224 
1225  if (!IS_PLAYER(actor) || IS_DEAD(actor))
1226  return;
1227 
1228  if(trigger.solid == SOLID_TRIGGER)
1229  {
1230  EXACTTRIGGER_TOUCH(this, trigger);
1231  }
1232 
1233  IL_EACH(g_items, it.enemy == actor && Item_IsLoot(it),
1234  {
1235  delete(it);
1236  });
1237 
1238  if(GiveItems(actor, 0, tokenize_console(this.netname)))
1239  centerprint(actor, this.message);
1240 }
1241 
1242 spawnfunc(target_items)
1243 {
1244  this.use = target_items_use;
1245  if(!this.strength_finished)
1246  this.strength_finished = autocvar_g_balance_powerup_strength_time;
1247  if(!this.invincible_finished)
1248  this.invincible_finished = autocvar_g_balance_powerup_invincible_time;
1249  if(!this.speed_finished)
1250  this.speed_finished = autocvar_g_balance_powerup_speed_time;
1251  if(!this.invisibility_finished)
1252  this.invisibility_finished = autocvar_g_balance_powerup_invisibility_time;
1253  if(!this.superweapons_finished)
1255 
1256  string str;
1257  int n = tokenize_console(this.netname);
1258  if(argv(0) == "give")
1259  {
1261  }
1262  else
1263  {
1264  for(int j = 0; j < n; ++j)
1265  {
1266  // this is from a time when unlimited superweapons were handled together with ammo in some parts of the code
1267  if (argv(j) == "unlimited_ammo") this.items |= IT_UNLIMITED_AMMO | IT_UNLIMITED_SUPERWEAPONS;
1268  else if(argv(j) == "unlimited_weapon_ammo") this.items |= IT_UNLIMITED_AMMO;
1269  else if(argv(j) == "unlimited_superweapons") this.items |= IT_UNLIMITED_SUPERWEAPONS;
1270  else if(argv(j) == "strength") this.items |= ITEM_Strength.m_itemid;
1271  else if(argv(j) == "invincible") this.items |= ITEM_Shield.m_itemid;
1272  else if(argv(j) == "speed") this.items |= ITEM_Speed.m_itemid;
1273  else if(argv(j) == "invisibility") this.items |= ITEM_Invisibility.m_itemid;
1274  else if(argv(j) == "superweapons") this.items |= IT_SUPERWEAPON;
1275  else if(argv(j) == "jetpack") this.items |= ITEM_Jetpack.m_itemid;
1276  else if(argv(j) == "fuel_regen") this.items |= ITEM_JetpackRegen.m_itemid;
1277  else
1278  {
1279  FOREACH(StatusEffect, it.instanceOfBuff,
1280  {
1281  string s = Buff_UndeprecateName(argv(j));
1282  if(s == it.netname)
1283  {
1284  this.buffdef = it;
1285  if(!this.buffs_finished)
1286  this.buffs_finished = it.m_time(it);
1287  break;
1288  }
1289  });
1290  FOREACH(Weapons, it != WEP_Null, {
1291  string s = W_UndeprecateName(argv(j));
1292  if(s == it.netname)
1293  {
1294  STAT(WEAPONS, this) |= (it.m_wepset);
1295  if(this.spawnflags == 0 || this.spawnflags == 2)
1296  it.wr_init(it);
1297  break;
1298  }
1299  });
1300  }
1301  }
1302 
1303  string itemprefix, valueprefix;
1304  if(this.spawnflags == 0)
1305  {
1306  itemprefix = "";
1307  valueprefix = "";
1308  }
1309  else if(this.spawnflags == 1)
1310  {
1311  itemprefix = "max ";
1312  valueprefix = "max ";
1313  }
1314  else if(this.spawnflags == 2)
1315  {
1316  itemprefix = "min ";
1317  valueprefix = "min ";
1318  }
1319  else if(this.spawnflags == 4)
1320  {
1321  itemprefix = "minus ";
1322  valueprefix = "max ";
1323  }
1324  else
1325  {
1326  error("invalid spawnflags");
1327  itemprefix = valueprefix = string_null;
1328  }
1329 
1330  str = "";
1331  str = sprintf("%s %s%d %s", str, itemprefix, boolean(this.items & IT_UNLIMITED_AMMO), "unlimited_weapon_ammo");
1332  str = sprintf("%s %s%d %s", str, itemprefix, boolean(this.items & IT_UNLIMITED_SUPERWEAPONS), "unlimited_superweapons");
1333  str = sprintf("%s %s%d %s", str, valueprefix, this.strength_finished * boolean(this.items & ITEM_Strength.m_itemid), "strength");
1334  str = sprintf("%s %s%d %s", str, valueprefix, this.invincible_finished * boolean(this.items & ITEM_Shield.m_itemid), "invincible");
1335  str = sprintf("%s %s%d %s", str, valueprefix, this.invisibility_finished * boolean(this.items & ITEM_Invisibility.m_itemid), "invisibility");
1336  str = sprintf("%s %s%d %s", str, valueprefix, this.speed_finished * boolean(this.items & ITEM_Speed.m_itemid), "speed");
1337  str = sprintf("%s %s%d %s", str, valueprefix, this.superweapons_finished * boolean(this.items & IT_SUPERWEAPON), "superweapons");
1338  str = sprintf("%s %s%d %s", str, itemprefix, boolean(this.items & ITEM_Jetpack.m_itemid), "jetpack");
1339  str = sprintf("%s %s%d %s", str, itemprefix, boolean(this.items & ITEM_JetpackRegen.m_itemid), "fuel_regen");
1340  float res;
1341  res = GetResource(this, RES_SHELLS); if(res != 0) str = sprintf("%s %s%d %s", str, valueprefix, max(0, res), "shells");
1342  res = GetResource(this, RES_BULLETS); if(res != 0) str = sprintf("%s %s%d %s", str, valueprefix, max(0, res), "nails");
1343  res = GetResource(this, RES_ROCKETS); if(res != 0) str = sprintf("%s %s%d %s", str, valueprefix, max(0, res), "rockets");
1344  res = GetResource(this, RES_CELLS); if(res != 0) str = sprintf("%s %s%d %s", str, valueprefix, max(0, res), "cells");
1345  res = GetResource(this, RES_PLASMA); if(res != 0) str = sprintf("%s %s%d %s", str, valueprefix, max(0, res), "plasma");
1346  res = GetResource(this, RES_FUEL); if(res != 0) str = sprintf("%s %s%d %s", str, valueprefix, max(0, res), "fuel");
1347  res = GetResource(this, RES_HEALTH); if(res != 0) str = sprintf("%s %s%d %s", str, valueprefix, max(0, res), "health");
1348  res = GetResource(this, RES_ARMOR); if(res != 0) str = sprintf("%s %s%d %s", str, valueprefix, max(0, res), "armor");
1349  FOREACH(StatusEffect, it.instanceOfBuff, str = sprintf("%s %s%d %s", str, valueprefix, this.buffs_finished * boolean(this.buffdef == it), it.netname));
1350  FOREACH(Weapons, it != WEP_Null, str = sprintf("%s %s%d %s", str, itemprefix, !!(STAT(WEAPONS, this) & (it.m_wepset)), it.netname));
1351  }
1352  this.netname = strzone(str);
1353 
1354  n = tokenize_console(this.netname);
1355  for(int j = 0; j < n; ++j)
1356  {
1357  FOREACH(Weapons, it != WEP_Null && W_UndeprecateName(argv(j)) == it.netname, {
1358  it.wr_init(it);
1359  break;
1360  });
1361  }
1362 }
1363 
1364 float GiveWeapon(entity e, float wpn, float op, float val)
1365 {
1366  WepSet v0, v1;
1367  WepSet s = WepSet_FromWeapon(REGISTRY_GET(Weapons, wpn));
1368  v0 = (STAT(WEAPONS, e) & s);
1369  switch(op)
1370  {
1371  case OP_SET:
1372  if(val > 0)
1373  STAT(WEAPONS, e) |= s;
1374  else
1375  STAT(WEAPONS, e) &= ~s;
1376  break;
1377  case OP_MIN:
1378  case OP_PLUS:
1379  if(val > 0)
1380  STAT(WEAPONS, e) |= s;
1381  break;
1382  case OP_MAX:
1383  if(val <= 0)
1384  STAT(WEAPONS, e) &= ~s;
1385  break;
1386  case OP_MINUS:
1387  if(val > 0)
1388  STAT(WEAPONS, e) &= ~s;
1389  break;
1390  }
1391  v1 = (STAT(WEAPONS, e) & s);
1392  return (v0 != v1);
1393 }
1394 
1395 bool GiveBuff(entity e, Buff thebuff, int op, int val)
1396 {
1397  bool had_buff = StatusEffects_active(thebuff, e);
1398  float new_buff_time = ((had_buff) ? StatusEffects_gettime(thebuff, e) : 0);
1399  switch (op)
1400  {
1401  case OP_SET:
1402  new_buff_time = val;
1403  break;
1404  case OP_MIN:
1405  new_buff_time = max(new_buff_time, val);
1406  break;
1407  case OP_MAX:
1408  new_buff_time = min(new_buff_time, val);
1409  break;
1410  case OP_PLUS:
1411  new_buff_time += val;
1412  break;
1413  case OP_MINUS:
1414  new_buff_time -= val;
1415  break;
1416  }
1417  if(new_buff_time <= 0)
1418  {
1419  if(had_buff) // only trigger removal mechanics if there is an effect to remove!
1420  StatusEffects_remove(thebuff, e, STATUSEFFECT_REMOVE_NORMAL);
1421  }
1422  else
1423  {
1424  buff_RemoveAll(e, STATUSEFFECT_REMOVE_CLEAR); // clear old buffs on the player first!
1425  StatusEffects_apply(thebuff, e, new_buff_time, 0);
1426  }
1427  bool have_buff = StatusEffects_active(thebuff, e);
1428  return (had_buff != have_buff);
1429 }
1430 
1431 void GiveSound(entity e, float v0, float v1, float t, Sound snd_incr, Sound snd_decr)
1432 {
1433  if(v1 == v0)
1434  return;
1435  if(v1 <= v0 - t)
1436  {
1437  if(snd_decr != NULL)
1438  sound(e, CH_TRIGGER, snd_decr, VOL_BASE, ATTEN_NORM);
1439  }
1440  else if(v0 >= v0 + t)
1441  {
1442  if(snd_incr != NULL)
1443  sound(e, ((snd_incr == SND_POWERUP) ? CH_TRIGGER_SINGLE : CH_TRIGGER), snd_incr, VOL_BASE, ATTEN_NORM);
1444  }
1445 }
1446 
1447 void GiveRot(entity e, float v0, float v1, .float rotfield, float rottime, .float regenfield, float regentime)
1448 {
1449  if(v0 < v1)
1450  e.(rotfield) = max(e.(rotfield), time + rottime);
1451  else if(v0 > v1)
1452  e.(regenfield) = max(e.(regenfield), time + regentime);
1453 }
1454 bool GiveResourceValue(entity e, Resource res_type, int op, int val)
1455 {
1456  int v0 = GetResource(e, res_type);
1457  float new_val = 0;
1458  switch (op)
1459  {
1460  // min 100 cells = at least 100 cells
1461  case OP_SET: new_val = val; break;
1462  case OP_MIN: new_val = max(v0, val); break;
1463  case OP_MAX: new_val = min(v0, val); break;
1464  case OP_PLUS: new_val = v0 + val; break;
1465  case OP_MINUS: new_val = v0 - val; break;
1466  default: return false;
1467  }
1468 
1469  return SetResourceExplicit(e, res_type, new_val);
1470 }
1471 bool GiveStatusEffect(entity e, StatusEffects this, int op, float val)
1472 {
1473  bool had_eff = StatusEffects_active(this, e);
1474  float new_eff_time = ((had_eff) ? StatusEffects_gettime(this, e) : 0);
1475  switch (op)
1476  {
1477  case OP_SET:
1478  new_eff_time = val;
1479  break;
1480  case OP_MIN:
1481  new_eff_time = max(new_eff_time, val);
1482  break;
1483  case OP_MAX:
1484  new_eff_time = min(new_eff_time, val);
1485  break;
1486  case OP_PLUS:
1487  new_eff_time += val;
1488  break;
1489  case OP_MINUS:
1490  new_eff_time -= val;
1491  break;
1492  }
1493  if(new_eff_time <= 0)
1494  {
1495  if(had_eff) // only trigger removal mechanics if there is an effect to remove!
1496  StatusEffects_remove(this, e, STATUSEFFECT_REMOVE_NORMAL);
1497  }
1498  else
1499  StatusEffects_apply(this, e, new_eff_time, 0);
1500  bool have_eff = StatusEffects_active(this, e);
1501  return (had_eff != have_eff);
1502 }
1503 
1504 float GiveItems(entity e, float beginarg, float endarg)
1505 {
1506  float got, i, val, op;
1507  string cmd;
1508 
1509  val = 999;
1510  op = OP_SET;
1511 
1512  got = 0;
1513 
1514  int _switchweapon = 0;
1515 
1516  if(CS_CVAR(e).cvar_cl_autoswitch)
1517  {
1518  for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
1519  {
1520  .entity weaponentity = weaponentities[slot];
1521  if(e.(weaponentity).m_weapon != WEP_Null || slot == 0)
1522  if(e.(weaponentity).m_switchweapon == w_getbestweapon(e, weaponentity))
1523  _switchweapon |= BIT(slot);
1524  }
1525  }
1526 
1527  if(e.statuseffects)
1528  {
1529  FOREACH(StatusEffect, true,
1530  {
1531  e.statuseffects.statuseffect_time[it.m_id] = max(0, e.statuseffects.statuseffect_time[it.m_id] - time);
1532  });
1533  }
1534 
1535  PREGIVE(e, items);
1536  PREGIVE_WEAPONS(e);
1537  PREGIVE_STATUSEFFECT(e, STATUSEFFECT_Strength);
1538  PREGIVE_STATUSEFFECT(e, STATUSEFFECT_Shield);
1539  PREGIVE_STATUSEFFECT(e, STATUSEFFECT_Speed);
1540  PREGIVE_STATUSEFFECT(e, STATUSEFFECT_Invisibility);
1541  //PREGIVE_STATUSEFFECT(e, STATUSEFFECT_Superweapons);
1542  PREGIVE_RESOURCE(e, RES_BULLETS);
1543  PREGIVE_RESOURCE(e, RES_CELLS);
1544  PREGIVE_RESOURCE(e, RES_PLASMA);
1545  PREGIVE_RESOURCE(e, RES_SHELLS);
1546  PREGIVE_RESOURCE(e, RES_ROCKETS);
1547  PREGIVE_RESOURCE(e, RES_FUEL);
1548  PREGIVE_RESOURCE(e, RES_ARMOR);
1550 
1551  for(i = beginarg; i < endarg; ++i)
1552  {
1553  cmd = argv(i);
1554 
1555  if(cmd == "0" || stof(cmd))
1556  {
1557  val = stof(cmd);
1558  continue;
1559  }
1560  switch(cmd)
1561  {
1562  case "no":
1563  op = OP_MAX;
1564  val = 0;
1565  continue;
1566  case "max":
1567  op = OP_MAX;
1568  continue;
1569  case "min":
1570  op = OP_MIN;
1571  continue;
1572  case "plus":
1573  op = OP_PLUS;
1574  continue;
1575  case "minus":
1576  op = OP_MINUS;
1577  continue;
1578  case "ALL":
1579  got += GiveBit(e, items, ITEM_JetpackRegen.m_itemid, op, val);
1580  FOREACH(StatusEffect, it.instanceOfPowerups, got += GiveStatusEffect(e, it, op, val));
1581  got += GiveBit(e, items, IT_UNLIMITED_AMMO | IT_UNLIMITED_SUPERWEAPONS, op, val);
1582  case "all":
1583  got += GiveBit(e, items, ITEM_Jetpack.m_itemid, op, val);
1584  got += GiveResourceValue(e, RES_HEALTH, op, val);
1585  got += GiveResourceValue(e, RES_ARMOR, op, val);
1586  case "allweapons":
1587  FOREACH(Weapons, it != WEP_Null && !(it.spawnflags & (WEP_FLAG_MUTATORBLOCKED | WEP_FLAG_SPECIALATTACK)), got += GiveWeapon(e, it.m_id, op, val));
1588  //case "allbuffs": // all buffs makes a player god, do not want!
1589  //FOREACH(StatusEffect, it.instanceOfBuff, got += GiveBuff(e, it, op, val));
1590  case "allammo":
1591  got += GiveResourceValue(e, RES_CELLS, op, val);
1592  got += GiveResourceValue(e, RES_PLASMA, op, val);
1593  got += GiveResourceValue(e, RES_SHELLS, op, val);
1594  got += GiveResourceValue(e, RES_BULLETS, op, val);
1595  got += GiveResourceValue(e, RES_ROCKETS, op, val);
1596  got += GiveResourceValue(e, RES_FUEL, op, val);
1597  break;
1598  case "unlimited_ammo":
1599  // this is from a time when unlimited superweapons were handled together with ammo in some parts of the code
1600  got += GiveBit(e, items, IT_UNLIMITED_AMMO | IT_UNLIMITED_SUPERWEAPONS, op, val);
1601  break;
1602  case "unlimited_weapon_ammo":
1603  got += GiveBit(e, items, IT_UNLIMITED_AMMO, op, val);
1604  break;
1605  case "unlimited_superweapons":
1606  got += GiveBit(e, items, IT_UNLIMITED_SUPERWEAPONS, op, val);
1607  break;
1608  case "jetpack":
1609  got += GiveBit(e, items, ITEM_Jetpack.m_itemid, op, val);
1610  break;
1611  case "fuel_regen":
1612  got += GiveBit(e, items, ITEM_JetpackRegen.m_itemid, op, val);
1613  break;
1614  case "strength":
1615  got += GiveStatusEffect(e, STATUSEFFECT_Strength, op, val);
1616  break;
1617  case "invincible":
1618  case "shield":
1619  got += GiveStatusEffect(e, STATUSEFFECT_Shield, op, val);
1620  break;
1621  case "speed":
1622  got += GiveStatusEffect(e, STATUSEFFECT_Speed, op, val);
1623  break;
1624  case "invisibility":
1625  got += GiveStatusEffect(e, STATUSEFFECT_Invisibility, op, val);
1626  break;
1627  case "superweapons":
1628  got += GiveStatusEffect(e, STATUSEFFECT_Superweapons, op, val);
1629  break;
1630  case "cells":
1631  got += GiveResourceValue(e, RES_CELLS, op, val);
1632  break;
1633  case "plasma":
1634  got += GiveResourceValue(e, RES_PLASMA, op, val);
1635  break;
1636  case "shells":
1637  got += GiveResourceValue(e, RES_SHELLS, op, val);
1638  break;
1639  case "nails":
1640  case "bullets":
1641  got += GiveResourceValue(e, RES_BULLETS, op, val);
1642  break;
1643  case "rockets":
1644  got += GiveResourceValue(e, RES_ROCKETS, op, val);
1645  break;
1646  case "health":
1647  got += GiveResourceValue(e, RES_HEALTH, op, val);
1648  break;
1649  case "armor":
1650  got += GiveResourceValue(e, RES_ARMOR, op, val);
1651  break;
1652  case "fuel":
1653  got += GiveResourceValue(e, RES_FUEL, op, val);
1654  break;
1655  default:
1656  FOREACH(StatusEffect, it.instanceOfBuff && buff_Available(it) && Buff_UndeprecateName(cmd) == it.netname,
1657  {
1658  got += GiveBuff(e, it, op, val);
1659  break;
1660  });
1661  FOREACH(Weapons, it != WEP_Null && W_UndeprecateName(cmd) == it.netname, {
1662  got += GiveWeapon(e, it.m_id, op, val);
1663  break;
1664  });
1665  break;
1666  }
1667  val = 999;
1668  op = OP_SET;
1669  }
1670 
1671  POSTGIVE_BIT(e, items, ITEM_JetpackRegen.m_itemid, SND_ITEMPICKUP, SND_Null);
1672  POSTGIVE_BIT(e, items, IT_UNLIMITED_SUPERWEAPONS, SND_POWERUP, SND_POWEROFF);
1673  POSTGIVE_BIT(e, items, IT_UNLIMITED_AMMO, SND_POWERUP, SND_POWEROFF);
1674  POSTGIVE_BIT(e, items, ITEM_Jetpack.m_itemid, SND_ITEMPICKUP, SND_Null);
1675  FOREACH(Weapons, it != WEP_Null, {
1676  POSTGIVE_WEAPON(e, it, SND_WEAPONPICKUP, SND_Null);
1677  if(!(save_weapons & (it.m_wepset)))
1678  if(STAT(WEAPONS, e) & (it.m_wepset))
1679  it.wr_init(it);
1680  });
1681  POSTGIVE_STATUSEFFECT(e, STATUSEFFECT_Strength, SND_POWERUP, SND_POWEROFF);
1682  POSTGIVE_STATUSEFFECT(e, STATUSEFFECT_Shield, SND_POWERUP, SND_POWEROFF);
1683  POSTGIVE_STATUSEFFECT(e, STATUSEFFECT_Speed, SND_POWERUP, SND_POWEROFF);
1684  POSTGIVE_STATUSEFFECT(e, STATUSEFFECT_Invisibility, SND_POWERUP, SND_POWEROFF);
1685  POSTGIVE_RESOURCE(e, RES_BULLETS, 0, SND_ITEMPICKUP, SND_Null);
1686  POSTGIVE_RESOURCE(e, RES_CELLS, 0, SND_ITEMPICKUP, SND_Null);
1687  POSTGIVE_RESOURCE(e, RES_PLASMA, 0, SND_ITEMPICKUP, SND_Null);
1688  POSTGIVE_RESOURCE(e, RES_SHELLS, 0, SND_ITEMPICKUP, SND_Null);
1689  POSTGIVE_RESOURCE(e, RES_ROCKETS, 0, SND_ITEMPICKUP, SND_Null);
1693 
1694  if(!StatusEffects_active(STATUSEFFECT_Superweapons, e))
1695  {
1696  if(!g_weaponarena && (STAT(WEAPONS, e) & WEPSET_SUPERWEAPONS))
1697  StatusEffects_apply(STATUSEFFECT_Superweapons, e, autocvar_g_balance_superweapons_time, 0);
1698  }
1699 
1700  if(e.statuseffects)
1701  {
1702  FOREACH(StatusEffect, true,
1703  {
1704  if(e.statuseffects.statuseffect_time[it.m_id] <= 0)
1705  e.statuseffects.statuseffect_time[it.m_id] = 0;
1706  else
1707  e.statuseffects.statuseffect_time[it.m_id] += time;
1708  });
1709 
1710  StatusEffects_update(e);
1711  }
1712 
1713  for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
1714  {
1715  .entity weaponentity = weaponentities[slot];
1716  if(e.(weaponentity).m_weapon != WEP_Null || slot == 0)
1717  if(!(STAT(WEAPONS, e) & WepSet_FromWeapon(e.(weaponentity).m_switchweapon)))
1718  _switchweapon |= BIT(slot);
1719  }
1720 
1721  if(_switchweapon)
1722  {
1723  for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
1724  {
1725  .entity weaponentity = weaponentities[slot];
1726  if(_switchweapon & BIT(slot))
1727  {
1728  Weapon wep = w_getbestweapon(e, weaponentity);
1729  if(wep != e.(weaponentity).m_switchweapon)
1730  W_SwitchWeapon_Force(e, wep, weaponentity);
1731  }
1732  }
1733  }
1734 
1735  return got;
1736 }
const int NUM_TEAMS
Number of teams in the game.
Definition: teams.qh:3
const float SOLID_NOT
Definition: csprogsdefs.qc:244
const int SPRITERULE_SPECTATOR
void buff_RemoveAll(entity actor, int removal_type)
Definition: sv_buffs.qc:286
float state
Definition: subs.qh:32
void Item_ItemsTime_SetTime(entity e, float t)
vector WepSet
Definition: weapon.qh:11
float autocvar_g_balance_pause_armor_rot
Definition: sv_resources.qh:32
#define IL_EACH(this, cond, body)
float MOVETYPE_NONE
Definition: progsdefs.qc:246
WepSet WEPSET_SUPERWEAPONS
Definition: all.qh:307
float colormap
Definition: csprogsdefs.qc:131
#define POSTGIVE_RESOURCE(e, f, t, snd_incr, snd_decr)
Definition: items.qh:119
float autocvar_g_balance_superweapons_time
Definition: items.qh:6
float autocvar_sv_simple_items
Definition: items.qh:19
void Item_Think(entity this)
Definition: items.qc:185
string string_null
Definition: nil.qh:9
bool have_pickup_item(entity this)
Definition: items.qc:98
void GiveRandomWeapons(entity receiver, int num_weapons, string weapon_names, entity ammo_entity)
Give several random weapons and ammo to the entity.
Definition: items.qc:406
void Item_ItemsTime_SetTimesForAllPlayers()
float autocvar_g_items_mindist
Definition: items.qh:8
void Item_FindTeam(entity this)
Definition: items.qc:749
float spawnshieldtime
Definition: damage.qh:64
float respawntimejitter
Definition: items.qh:37
void W_SwitchWeapon_Force(Player this, Weapon w,.entity weaponentity)
Definition: selection.qc:243
float respawntime
Definition: items.qh:36
float IT_KEY2
Definition: progsdefs.qc:308
skin
Definition: ent_cs.qc:143
#define SND(id)
Definition: all.qh:35
float item_respawncounter
Definition: items.qh:40
bool SetResourceExplicit(entity e, Resource res_type, float amount)
Sets the resource amount of an entity without calling any hooks.
Definition: cl_resources.qc:15
float autocvar_g_balance_pause_health_regen
Definition: sv_resources.qh:35
entity item_model_ent
Definition: items.qh:29
float(entity, float) PlayerPhysplug
#define w_getbestweapon(ent, wepent)
Definition: selection.qh:23
#define Sound_fixpath(this)
Definition: sound.qh:141
float g_pickup_nails_max
Definition: world.qh:70
bool is_item
Definition: items.qh:93
void target_items_use(entity this, entity actor, entity trigger)
Definition: items.qc:1216
int team
Definition: main.qh:157
float MOVETYPE_TOSS
Definition: progsdefs.qc:252
ERASEABLE void RandomSelection_Init()
Definition: random.qc:4
#define EXACTTRIGGER_TOUCH(e, t)
Definition: common.qh:116
void TeamBalance_Destroy(entity balance)
Destroy the team balance entity.
Definition: teamplay.qc:627
vector oldorigin
Definition: csprogsdefs.qc:102
entity() spawn
#define PREGIVE_RESOURCE(e, f)
Definition: items.qh:115
#define REGISTRY_GET(id, i)
Definition: registry.qh:43
void Item_ScheduleInitialRespawn(entity e)
Definition: items.qc:371
const float MOVE_NORMAL
Definition: csprogsdefs.qc:252
void Item_Respawn(entity this)
Definition: items.qc:198
bool Item_ItemsTime_Allow(GameItem it)
Definition: itemstime.qc:64
#define FOREACH_CLIENT(cond, body)
Definition: utils.qh:49
float fade_start
Definition: models.qh:23
#define CS_CVAR(this)
Definition: state.qh:51
void SUB_UseTargets(entity this, entity actor, entity trigger)
Definition: triggers.qc:366
bool autocvar_g_fullbrightitems
Definition: items.qh:7
string netname
Definition: powerups.qc:20
int autocvar_spawn_debug
Definition: client.qh:50
Effect is being removed by a function, calls regular removal mechanics.
Definition: all.qh:25
float ammo_pickupevalfunc(entity player, entity item)
Definition: items.qc:821
float bot_pickupbasevalue
Definition: bot.qh:66
float generic_pickupevalfunc(entity player, entity item)
Definition: items.qc:797
entity to
Definition: self.qh:96
origin
Definition: ent_cs.qc:114
Definition: pickup.qh:22
float autocvar_g_balance_pause_fuel_regen
Definition: sv_resources.qh:33
#define droptofloor
Definition: pre.qh:5
int autocvar_g_powerups
Definition: sv_powerups.qh:7
string classname
Definition: csprogsdefs.qc:107
const float EF_NODEPTHTEST
Definition: csprogsdefs.qc:304
int m_id
Definition: item.qh:105
float noalign
Definition: items.qh:42
float item_spawnshieldtime
Definition: items.qh:47
float FL_ITEM
Definition: progsdefs.qc:239
#define POSTGIVE_RES_ROT(e, f, t, rotfield, rottime, regenfield, regentime, snd_incr, snd_decr)
Definition: items.qh:120
float effects
Definition: csprogsdefs.qc:111
Definition: bits.qh:79
string Buff_UndeprecateName(string buffname)
Definition: all.inc:1
float spawnflags
Definition: progsdefs.qc:191
int group_count
Definition: items.qc:1169
entity owner
Definition: main.qh:73
float Item_ItemsTime_UpdateTime(entity e, float t)
void _StartItem(entity this, entity def, float defaultrespawntime, float defaultrespawntimejitter)
Definition: items.qc:925
string model
Definition: csprogsdefs.qc:108
#define IS_REAL_CLIENT(v)
Definition: utils.qh:17
void Item_ScheduleRespawnIn(entity e, float t)
Definition: items.qc:286
void TakeResourceWithLimit(entity receiver, Resource res_type, float amount, float limit)
Takes an entity some resource but not less than a limit.
Definition: cl_resources.qc:40
const float EF_ADDITIVE
Definition: csprogsdefs.qc:300
#define setmodel(this, m)
Definition: model.qh:26
RES_HEALTH
Definition: ent_cs.qc:126
const float EF_NODRAW
Definition: csprogsdefs.qc:305
float ammo
Definition: sv_turrets.qh:44
const float EF_FULLBRIGHT
Definition: csprogsdefs.qc:303
Effect is being forcibly removed without calling any additional mechanics.
Definition: all.qh:27
#define argv_end_index
Definition: dpextensions.qh:30
Definition: bits.qh:78
bool GiveStatusEffect(entity e, StatusEffects this, int op, float val)
Definition: items.qc:1471
#define BIT(n)
Only ever assign into the first 24 bits in QC (so max is BIT(23)).
Definition: bits.qh:8
Definition: bits.qh:77
Definition: buffs.qh:20
entity msg_entity
Definition: progsdefs.qc:63
float cnt
Definition: powerups.qc:24
#define g_cts
Definition: cts.qh:36
float weapon_pickupevalfunc(entity player, entity item)
Definition: items.qc:799
ERASEABLE entity IL_PUSH(IntrusiveList this, entity it)
Push to tail.
float weapon
Definition: progsdefs.qc:139
#define PREGIVE_STATUSEFFECT(e, f)
Definition: items.qh:114
void item_use(entity this, entity actor, entity trigger)
Definition: items.qc:919
void GiveResourceWithLimit(entity receiver, Resource res_type, float amount, float limit)
Gives an entity some resource but not more than a limit.
void W_GiveWeapon(entity e, int wep)
Definition: common.qc:33
#define argv_start_index
Definition: dpextensions.qh:27
const int MAX_WEAPONSLOTS
Definition: weapon.qh:13
void StartItem(entity this, GameItem def)
Definition: items.qc:1148
Definition: bits.qh:80
void GiveRot(entity e, float v0, float v1,.float rotfield, float rottime,.float regenfield, float regentime)
Definition: items.qc:1447
void TeamBalance_GetTeamCounts(entity balance, entity ignore)
Counts the number of players and various other information about each team.
Definition: teamplay.qc:681
const int CH_TRIGGER
Definition: sound.qh:12
float pauserothealth_finished
Definition: client.qh:343
const float ITEM_RESPAWN_TICKS
Definition: items.qh:24
entity RandomSelection_chosen_ent
Definition: random.qh:5
IntrusiveList g_items
Definition: items.qh:126
float autocvar_g_items_maxdist
Definition: items.qh:9
#define POSTGIVE_BIT(e, f, b, snd_incr, snd_decr)
Definition: items.qh:117
float g_pickup_rockets_max
Definition: world.qh:71
float bot_pickup
Definition: api.qh:43
float wait
Definition: subs.qh:39
float pauserotfuel_finished
Definition: client.qh:345
void RemoveItem(entity this)
Definition: items.qc:787
string message
Definition: powerups.qc:19
#define NULL
Definition: post.qh:17
entity itemdef
Definition: items.qh:94
bool GiveBuff(entity e, Buff thebuff, int op, int val)
Definition: items.qc:1395
float trace_dpstartcontents
float IT_KEY1
Definition: progsdefs.qc:307
#define crandom()
Returns a random number between -1.0 and 1.0.
Definition: math.qh:27
Definition: model.qh:3
const float VOL_BASE
Definition: sound.qh:36
float pauserotarmor_finished
Definition: client.qh:344
bool autocvar_g_powerups_stack
Definition: sv_powerups.qh:9
float pickup_anyway
Definition: items.qh:32
float g_pickup_fuel_max
Definition: world.qh:74
float takedamage
Definition: progsdefs.qc:147
float g_pickup_shells_max
Definition: world.qh:69
void Item_Touch(entity this, entity toucher)
Definition: items.qc:631
void UpdateItemAfterTeleport(entity this)
Definition: items.qc:92
Definition: sound.qh:119
float autocvar_g_items_dropped_lifetime
Definition: items.qh:10
#define M_ARGV(x, type)
Definition: events.qh:17
#define IS_DEAD(s)
Definition: utils.qh:26
const float ATTEN_NORM
Definition: sound.qh:30
float nextthink
Definition: csprogsdefs.qc:121
void ItemUpdate(entity this)
Definition: items.qc:86
bool autocvar_g_nodepthtestitems
Definition: items.qh:12
const int CH_TRIGGER_SINGLE
Definition: sound.qh:13
void setItemGroup(entity this)
Definition: items.qc:1171
bool ItemSend(entity this, entity to, int sf)
Definition: items.qc:31
Definition: bits.qh:81
bool Item_ItemsTime_SpectatorOnly(GameItem it)
Definition: itemstime.qc:56
float autocvar_g_balance_pause_health_rot
Definition: sv_resources.qh:36
string W_UndeprecateName(string s)
Definition: all.qc:110
#define CENTER_OR_VIEWOFS(ent)
Definition: utils.qh:28
vector(float skel, float bonenum) _skel_get_boneabs_hidden
#define tokenize_console
Definition: dpextensions.qh:24
float gravity
Definition: items.qh:16
#define ITEM_DAMAGE_NEEDKILL(dt)
Definition: items.qh:130
void GiveResource(entity receiver, Resource res_type, float amount)
Gives an entity some resource.
spawnfunc(target_items)
Definition: items.qc:1242
entity players
Definition: main.qh:43
float superweapons_finished
Definition: items.qh:44
bool GiveResourceValue(entity e, Resource res_type, int op, int val)
Definition: items.qc:1454
AUTOCVAR(g_pickup_respawntime_scaling_reciprocal, float, 0.0, "Multiply respawn time by `reciprocal / (p + offset) + linear` where `p` is the current number of players, takes effect with 2 or more players present, `reciprocal` (with `offset` and `linear` set to 0) can be used to achieve a constant number of items spawned *per player*")
float healtharmor_pickupevalfunc(entity player, entity item)
Definition: items.qc:889
float GetResource(entity e, Resource res_type)
Returns the current amount of resource the given entity has.
Definition: cl_resources.qc:10
#define ITEM_TOUCH_NEEDKILL()
Definition: items.qh:129
float flags
Definition: csprogsdefs.qc:129
void InitializeEntity(entity e, void(entity this) func, int order)
Definition: world.qc:2146
bool TeamBalance_IsTeamAllowed(entity balance, int index)
Returns whether the team change to the specified team is allowed.
Definition: teamplay.qc:662
const int WEP_FLAG_SPECIALATTACK
Definition: weapon.qh:211
bool startitem_failed
Definition: spawning.qh:7
float count
Definition: powerups.qc:22
float g_pickup_plasma_max
Definition: world.qh:73
#define LOG_TRACE(...)
Definition: log.qh:81
#define getSendEntity(e)
Definition: self.qh:98
#define ITEM_HANDLE(signal,...)
Definition: item.qh:103
bool Item_GiveAmmoTo(entity item, entity player, Resource res_type, float ammomax)
Definition: items.qc:451
void Item_RespawnCountdown(entity this)
Definition: items.qc:218
#define PREGIVE(e, f)
Definition: items.qh:113
float items
Definition: progsdefs.qc:145
#define _sound(e, c, s, v, a)
Definition: sound.qh:50
const float SOLID_TRIGGER
Definition: csprogsdefs.qc:245
void Item_Show(entity e, int mode)
Definition: items.qc:120
float g_weapon_stay
Definition: world.qh:112
string targetname
Definition: progsdefs.qc:194
#define MUTATOR_CALLHOOK(id,...)
Definition: base.qh:140
#define LABEL(id)
Definition: compiler.qh:36
vector pos1
Definition: subs.qh:50
entity weaponentities[MAX_WEAPONSLOTS]
Definition: weapon.qh:14
#define POSTGIVE_STATUSEFFECT(e, f, snd_incr, snd_decr)
Definition: items.qh:118
float DPCONTENTS_NODROP
bool Item_GiveTo(entity item, entity player)
Definition: items.qc:479
void setItemGroupCount()
Definition: items.qc:1205
setorigin(ent, v)
bool Item_IsLoot(entity item)
Returns whether the item is loot.
Definition: spawning.qc:121
float pauseregen_finished
Definition: client.qh:342
#define setthink(e, f)
int TeamBalance_GetNumberOfPlayers(entity balance, int index)
Returns the number of players (both humans and bots) in a team.
Definition: teamplay.qc:763
float GiveItems(entity e, float beginarg, float endarg)
Definition: items.qc:1504
vector angles
Definition: csprogsdefs.qc:104
float GiveWeapon(entity e, float wpn, float op, float val)
Definition: items.qc:1364
int autocvar_g_pickup_items
Definition: items.qh:11
#define use
Definition: csprogsdefs.qh:50
const int WEP_FLAG_MUTATORBLOCKED
Definition: weapon.qh:203
entity TeamBalance_CheckAllowedTeams(entity for_whom)
Checks whether the player can join teams according to global configuration and mutator settings...
Definition: teamplay.qc:487
#define WepSet_FromWeapon(it)
Definition: all.qh:38
string target
Definition: progsdefs.qc:193
#define sound(e, c, s, v, a)
Definition: sound.qh:52
ERASEABLE bool GiveBit(entity e,.int fld, int bit, int op, int val)
Definition: bits.qh:85
void waypoint_spawnforitem(entity e)
Definition: waypoints.qc:2007
float buff_Available(entity buff)
Definition: sv_buffs.qc:257
vector glowmod
fields which are explicitly/manually set are marked with "M", fields set automatically are marked wit...
Definition: weapon.qh:41
float g_pickup_cells_max
Definition: world.qh:72
float time
Definition: csprogsdefs.qc:16
vector velocity
Definition: csprogsdefs.qc:103
bool Item_IsExpiring(entity item)
Returns whether the item is expiring (i.e.
Definition: spawning.qc:136
void GiveSound(entity e, float v0, float v1, float t, Sound snd_incr, Sound snd_decr)
Definition: items.qc:1431
float fade_end
Definition: models.qh:23
#define IS_SMALL(def)
Definition: items.qc:1168
entity item_pickupsound_ent
Definition: items.qh:28
#define FOREACH(list, cond, body)
Definition: iter.qh:19
#define PREGIVE_WEAPONS(e)
Definition: items.qh:112
string item_pickupsound
Definition: items.qh:27
void Item_ScheduleRespawn(entity e)
Definition: items.qc:351
void set_movetype(entity this, int mt)
#define IS_PLAYER(v)
Definition: utils.qh:9
#define POSTGIVE_WEAPON(e, b, snd_incr, snd_decr)
Definition: items.qh:116
const float EF_STARDUST
Definition: csprogsdefs.qc:308
void Item_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype,.entity weaponentity, vector hitloc, vector force)
Definition: items.qc:913
void Item_Reset(entity this)
Definition: items.qc:728
float solid
Definition: csprogsdefs.qc:99
float DAMAGE_YES
Definition: progsdefs.qc:283
void Item_RespawnThink(entity this)
Definition: items.qc:276
float g_weaponarena
Definition: world.qh:76
float autocvar_g_balance_pause_fuel_rot
Definition: sv_resources.qh:34
float adjust_respawntime(float normal_respawntime)
Adjust respawn time according to the number of players.
Definition: items.qc:323