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