]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/server/t_items.qc
Merge branch 'master' into terencehill/itemstime
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / t_items.qc
1 #ifdef CSQC
2 void ItemDraw()
3 {
4     if(self.gravity)
5     {
6         Movetype_Physics_MatchServer(autocvar_cl_projectiles_sloppy);
7         if(self.move_flags & FL_ONGROUND)
8         { // For some reason move_avelocity gets set to '0 0 0' here ...
9             self.oldorigin = self.origin;
10             self.gravity = 0;
11
12             if(autocvar_cl_animate_items)
13             { // ... so reset it if animations are requested.
14                 if(self.ItemStatus & ITS_ANIMATE1)
15                     self.move_avelocity = '0 180 0';
16
17                 if(self.ItemStatus & ITS_ANIMATE2)
18                     self.move_avelocity = '0 -90 0';
19             }
20         }
21     }
22     else if (autocvar_cl_animate_items)
23     {
24         if(self.ItemStatus & ITS_ANIMATE1)
25         {
26             self.angles += self.move_avelocity * frametime;
27             setorigin(self, '0 0 10' + self.oldorigin + '0 0 8' * sin(time * 2));
28         }
29
30         if(self.ItemStatus & ITS_ANIMATE2)
31         {
32             self.angles += self.move_avelocity * frametime;
33             setorigin(self, '0 0 8' + self.oldorigin + '0 0 4' * sin(time * 3));
34         }
35     }
36 }
37
38 void ItemDrawSimple()
39 {
40     if(self.gravity)
41     {
42         Movetype_Physics_MatchServer(autocvar_cl_projectiles_sloppy);
43
44         if(self.move_flags & FL_ONGROUND)
45             self.gravity = 0;
46     }
47 }
48
49 void ItemRead(float _IsNew)
50 {
51     float sf = ReadByte();
52
53     if(sf & ISF_LOCATION)
54     {
55         self.origin_x = ReadCoord();
56         self.origin_y = ReadCoord();
57         self.origin_z = ReadCoord();
58         setorigin(self, self.origin);
59         self.oldorigin = self.origin;
60     }
61
62     if(sf & ISF_ANGLES)
63     {
64         self.angles_x = ReadCoord();
65         self.angles_y = ReadCoord();
66         self.angles_z = ReadCoord();
67         self.move_angles = self.angles;
68     }
69
70     if(sf & ISF_SIZE)
71     {
72         self.mins_x = ReadCoord();
73         self.mins_y = ReadCoord();
74         self.mins_z = ReadCoord();
75         self.maxs_x = ReadCoord();
76         self.maxs_y = ReadCoord();
77         self.maxs_z = ReadCoord();
78         setsize(self, self.mins, self.maxs);
79     }
80
81     if(sf & ISF_STATUS) // need to read/write status frist so model can handle simple, fb etc.
82     {
83         self.ItemStatus = ReadByte();
84
85         if(self.ItemStatus & ITS_AVAILABLE)
86         {
87             self.alpha = 1;
88             self.colormod = self.glowmod = '1 1 1';
89         }
90         else
91         {
92             if (autocvar_cl_ghost_items_color)
93             {
94                 self.alpha = autocvar_cl_ghost_items;
95                 self.colormod = self.glowmod = autocvar_cl_ghost_items_color;
96             }
97             else
98                 self.alpha = -1;
99         }
100
101         if(autocvar_cl_fullbright_items)
102             if(self.ItemStatus & ITS_ALLOWFB)
103                 self.effects |= EF_FULLBRIGHT;
104
105         if(self.ItemStatus & ITS_STAYWEP)
106         {
107             self.colormod = self.glowmod = autocvar_cl_weapon_stay_color;
108             self.alpha = autocvar_cl_weapon_stay_alpha;
109
110         }
111
112         if(self.ItemStatus & ITS_POWERUP)
113         {
114             if(self.ItemStatus & ITS_AVAILABLE)
115                 self.effects |= (EF_ADDITIVE | EF_FULLBRIGHT);
116             else
117                  self.effects &= ~(EF_ADDITIVE | EF_FULLBRIGHT);
118         }
119     }
120
121     if(sf & ISF_MODEL)
122     {
123         self.drawmask  = MASK_NORMAL;
124         self.movetype  = MOVETYPE_TOSS;
125         self.draw       = ItemDraw;
126
127         if(self.mdl)
128             strunzone(self.mdl);
129
130         self.mdl = "";
131         string _fn = ReadString();
132
133         if(autocvar_cl_simple_items && (self.ItemStatus & ITS_ALLOWSI))
134         {
135             string _fn2 = substring(_fn, 0 , strlen(_fn) -4);
136             self.draw = ItemDrawSimple;
137
138
139
140             if(fexists(sprintf("%s%s.md3", _fn2, autocvar_cl_simpleitems_postfix)))
141                 self.mdl = strzone(sprintf("%s%s.md3", _fn2, autocvar_cl_simpleitems_postfix));
142             else if(fexists(sprintf("%s%s.dpm", _fn2, autocvar_cl_simpleitems_postfix)))
143                 self.mdl = strzone(sprintf("%s%s.dpm", _fn2, autocvar_cl_simpleitems_postfix));
144             else if(fexists(sprintf("%s%s.iqm", _fn2, autocvar_cl_simpleitems_postfix)))
145                 self.mdl = strzone(sprintf("%s%s.iqm", _fn2, autocvar_cl_simpleitems_postfix));
146             else if(fexists(sprintf("%s%s.obj", _fn2, autocvar_cl_simpleitems_postfix)))
147                 self.mdl = strzone(sprintf("%s%s.obj", _fn2, autocvar_cl_simpleitems_postfix));
148             else
149             {
150                 self.draw = ItemDraw;
151                 dprint("Simple item requested for ", _fn, " but no model exsist for it\n");
152             }
153         }
154
155         if(self.draw != ItemDrawSimple)
156             self.mdl = strzone(_fn);
157
158
159         if(self.mdl == "")
160             dprint("^1WARNING!^7 self.mdl is unset for item ", self.classname, " tell tZork aboute this!\n");
161
162         precache_model(self.mdl);
163         setmodel(self, self.mdl);
164     }
165
166     if(sf & ISF_COLORMAP)
167         self.colormap = ReadShort();
168
169     if(sf & ISF_DROP)
170     {
171         self.gravity = 1;
172         //self.move_angles = '0 0 0';
173         self.move_movetype = MOVETYPE_TOSS;
174         self.move_velocity_x = ReadCoord();
175         self.move_velocity_y = ReadCoord();
176         self.move_velocity_z = ReadCoord();
177         self.velocity = self.move_velocity;
178         self.move_origin = self.oldorigin;
179
180         if(!self.move_time)
181         {
182             self.move_time = time;
183             self.spawntime = time;
184         }
185         else
186             self.move_time = max(self.move_time, time);
187     }
188
189     if(autocvar_cl_animate_items)
190     {
191         if(self.ItemStatus & ITS_ANIMATE1)
192             self.move_avelocity = '0 180 0';
193
194         if(self.ItemStatus & ITS_ANIMATE2)
195             self.move_avelocity = '0 -90 0';
196     }
197 }
198
199 #endif
200
201 #ifdef SVQC
202 float ItemSend(entity to, float sf)
203 {
204     if(self.gravity)
205         sf |= ISF_DROP;
206     else
207         sf &= ~ISF_DROP;
208
209         WriteByte(MSG_ENTITY, ENT_CLIENT_ITEM);
210         WriteByte(MSG_ENTITY, sf);
211
212         //WriteByte(MSG_ENTITY, self.cnt);
213     if(sf & ISF_LOCATION)
214     {
215         WriteCoord(MSG_ENTITY, self.origin_x);
216         WriteCoord(MSG_ENTITY, self.origin_y);
217         WriteCoord(MSG_ENTITY, self.origin_z);
218     }
219
220     if(sf & ISF_ANGLES)
221     {
222         WriteCoord(MSG_ENTITY, self.angles_x);
223         WriteCoord(MSG_ENTITY, self.angles_y);
224         WriteCoord(MSG_ENTITY, self.angles_z);
225     }
226
227     if(sf & ISF_SIZE)
228     {
229         WriteCoord(MSG_ENTITY, self.mins_x);
230         WriteCoord(MSG_ENTITY, self.mins_y);
231         WriteCoord(MSG_ENTITY, self.mins_z);
232         WriteCoord(MSG_ENTITY, self.maxs_x);
233         WriteCoord(MSG_ENTITY, self.maxs_y);
234         WriteCoord(MSG_ENTITY, self.maxs_z);
235     }
236
237     if(sf & ISF_STATUS)
238         WriteByte(MSG_ENTITY, self.ItemStatus);
239
240     if(sf & ISF_MODEL)
241     {
242
243         if(self.mdl == "")
244             dprint("^1WARNING!^7 self.mdl is unset for item ", self.classname, "exspect a crash just aboute now\n");
245
246         WriteString(MSG_ENTITY, self.mdl);
247     }
248
249
250     if(sf & ISF_COLORMAP)
251         WriteShort(MSG_ENTITY, self.colormap);
252
253     if(sf & ISF_DROP)
254     {
255         WriteCoord(MSG_ENTITY, self.velocity_x);
256         WriteCoord(MSG_ENTITY, self.velocity_y);
257         WriteCoord(MSG_ENTITY, self.velocity_z);
258     }
259
260     return TRUE;
261 }
262
263 void ItemUpdate(entity item)
264 {
265         item.SendFlags |= ISF_LOCATION;
266 }
267
268 float have_pickup_item(void)
269 {
270         if(self.flags & FL_POWERUP)
271         {
272                 if(autocvar_g_powerups > 0)
273                         return TRUE;
274                 if(autocvar_g_powerups == 0)
275                         return FALSE;
276         }
277         else
278         {
279                 if(autocvar_g_pickup_items > 0)
280                         return TRUE;
281                 if(autocvar_g_pickup_items == 0)
282                         return FALSE;
283                 if(g_weaponarena)
284                         if(self.weapons || (self.items & IT_AMMO)) // no item or ammo pickups in weaponarena
285                                 return FALSE;
286         }
287         return TRUE;
288 }
289
290 /*
291 float Item_Customize()
292 {
293         if(self.spawnshieldtime)
294                 return TRUE;
295         if(self.weapons & ~other.weapons)
296         {
297                 self.colormod = '0 0 0';
298                 self.glowmod = self.colormod;
299                 self.alpha = 0.5 + 0.5 * g_ghost_items; // halfway more alpha
300                 return TRUE;
301         }
302         else
303         {
304                 if(g_ghost_items)
305                 {
306                         self.colormod = stov(autocvar_g_ghost_items_color);
307                         self.glowmod = self.colormod;
308                         self.alpha = g_ghost_items;
309                         return TRUE;
310                 }
311                 else
312                         return FALSE;
313         }
314 }
315 */
316
317 void Item_Show (entity e, float mode)
318 {
319         e.effects &= ~(EF_ADDITIVE | EF_STARDUST | EF_FULLBRIGHT | EF_NODEPTHTEST);
320         e.ItemStatus &= ~ITS_STAYWEP;
321         if (mode > 0)
322         {
323                 // make the item look normal, and be touchable
324                 e.model = e.mdl;
325                 e.solid = SOLID_TRIGGER;
326                 e.spawnshieldtime = 1;
327                 e.ItemStatus |= ITS_AVAILABLE;
328         }
329         else if (mode < 0)
330         {
331                 // hide the item completely
332                 e.model = string_null;
333                 e.solid = SOLID_NOT;
334                 e.spawnshieldtime = 1;
335                 e.ItemStatus &= ~ITS_AVAILABLE;
336         }
337         else if((e.flags & FL_WEAPON) && !(e.flags & FL_NO_WEAPON_STAY) && g_weapon_stay)
338         {
339                 // make the item translucent and not touchable
340                 e.model = e.mdl;
341                 e.solid = SOLID_TRIGGER; // can STILL be picked up!
342                 e.effects |= EF_STARDUST;
343                 e.spawnshieldtime = 0; // field indicates whether picking it up may give you anything other than the weapon
344                 e.ItemStatus |= (ITS_AVAILABLE | ITS_STAYWEP);
345         }
346         else
347         {
348                 //setmodel(e, "null");
349                 e.solid = SOLID_NOT;
350                 e.colormod = '0 0 0';
351                 e.glowmod = e.colormod;
352                 e.spawnshieldtime = 1;
353                 e.ItemStatus &= ~ITS_AVAILABLE;
354         }
355
356         if (e.items & IT_STRENGTH || e.items & IT_INVINCIBLE)
357             e.ItemStatus |= ITS_POWERUP;
358
359         if (autocvar_g_nodepthtestitems)
360                 e.effects |= EF_NODEPTHTEST;
361
362
363     if (autocvar_g_fullbrightitems)
364                 e.ItemStatus |= ITS_ALLOWFB;
365
366         if (autocvar_sv_simple_items)
367         e.ItemStatus |= ITS_ALLOWSI;
368
369         // relink entity (because solid may have changed)
370         setorigin(e, e.origin);
371     e.SendFlags |= ISF_STATUS;
372 }
373
374 void Item_Think()
375 {
376         self.nextthink = time;
377         if(self.origin != self.oldorigin)
378         {
379                 self.oldorigin = self.origin;
380                 ItemUpdate(self);
381         }
382 }
383
384 float it_armor_large_time;
385 float it_health_mega_time;
386 float it_invisible_time;
387 float it_speed_time;
388 float it_extralife_time;
389 float it_strength_time;
390 float it_shield_time;
391 float it_fuelregen_time;
392 float it_jetpack_time;
393 float it_superweapons_time;
394
395 void Item_ItemsTime_Init()
396 {
397         it_armor_large_time = -1;
398         it_health_mega_time = -1;
399         it_invisible_time = -1;
400         it_speed_time = -1;
401         it_extralife_time = -1;
402         it_strength_time = -1;
403         it_shield_time = -1;
404         it_fuelregen_time = -1;
405         it_jetpack_time = -1;
406         it_superweapons_time = -1;
407 }
408 void Item_ItemsTime_Reset()
409 {
410         it_armor_large_time = (it_armor_large_time == -1) ? -1 : 0;
411         it_health_mega_time = (it_health_mega_time == -1) ? -1 : 0;
412         it_invisible_time   = (it_invisible_time   == -1) ? -1 : 0;
413         it_speed_time       = (it_speed_time       == -1) ? -1 : 0;
414         it_extralife_time   = (it_extralife_time   == -1) ? -1 : 0;
415         it_strength_time    = (it_strength_time    == -1) ? -1 : 0;
416         it_shield_time      = (it_shield_time      == -1) ? -1 : 0;
417         it_fuelregen_time   = (it_fuelregen_time   == -1) ? -1 : 0;
418         it_jetpack_time     = (it_jetpack_time     == -1) ? -1 : 0;
419         it_superweapons_time= (it_superweapons_time== -1) ? -1 : 0;
420 }
421 void Item_ItemsTime_ResetForPlayer(entity e)
422 {
423         e.item_armor_large_time = (it_armor_large_time == -1) ? -1 : 0;
424         e.item_health_mega_time = (it_health_mega_time == -1) ? -1 : 0;
425         e.item_invisible_time   = (it_invisible_time   == -1) ? -1 : 0;
426         e.item_speed_time       = (it_speed_time       == -1) ? -1 : 0;
427         e.item_extralife_time   = (it_extralife_time   == -1) ? -1 : 0;
428         e.item_strength_time    = (it_strength_time    == -1) ? -1 : 0;
429         e.item_shield_time      = (it_shield_time      == -1) ? -1 : 0;
430         e.item_fuelregen_time   = (it_fuelregen_time   == -1) ? -1 : 0;
431         e.item_jetpack_time     = (it_jetpack_time     == -1) ? -1 : 0;
432         e.item_superweapons_time= (it_superweapons_time== -1) ? -1 : 0;
433 }
434 void Item_ItemsTime_Get(entity e)
435 {
436         e.item_armor_large_time = it_armor_large_time;
437         e.item_health_mega_time = it_health_mega_time;
438         e.item_invisible_time = it_invisible_time;
439         e.item_speed_time = it_speed_time;
440         e.item_extralife_time = it_extralife_time;
441         e.item_strength_time = it_strength_time;
442         e.item_shield_time = it_shield_time;
443         e.item_fuelregen_time = it_fuelregen_time;
444         e.item_jetpack_time = it_jetpack_time;
445         e.item_superweapons_time = it_superweapons_time;
446 }
447 float Item_ItemsTime_UpdateTime_Check(float item_time, float t)
448 {
449         if(t == 0 && item_time == -1)
450                 return TRUE;
451         if(time < t && (item_time <= time || t < item_time))
452                 return TRUE;
453         return FALSE;
454 }
455 void Item_ItemsTime_UpdateTime(entity e, float t)
456 {
457         if(g_instagib)
458         {
459                 switch(e.items)
460                 {
461                         case IT_STRENGTH://"item-invis"
462                                 if(Item_ItemsTime_UpdateTime_Check(it_invisible_time, t))
463                                         it_invisible_time = t;
464                                 break;
465                         case IT_NAILS://"item-extralife"
466                                 if(Item_ItemsTime_UpdateTime_Check(it_extralife_time, t))
467                                         it_extralife_time = t;
468                                 break;
469                         case IT_INVINCIBLE://"item-speed"
470                                 if(Item_ItemsTime_UpdateTime_Check(it_speed_time, t))
471                                         it_speed_time = t;
472                                 break;
473                 }
474         }
475         else
476         {
477                 switch(e.items)
478                 {
479                         case IT_HEALTH:
480                                 //if (e.classname == "item_health_mega")
481                                         if(Item_ItemsTime_UpdateTime_Check(it_health_mega_time, t))
482                                                 it_health_mega_time = t;
483                                 break;
484                         case IT_ARMOR:
485                                 if (e.classname == "item_armor_large")
486                                         if(Item_ItemsTime_UpdateTime_Check(it_armor_large_time, t))
487                                                 it_armor_large_time = t;
488                                 break;
489                         case IT_STRENGTH://"item-strength"
490                                 if(Item_ItemsTime_UpdateTime_Check(it_strength_time, t))
491                                         it_strength_time = t;
492                                 break;
493                         case IT_INVINCIBLE://"item-shield"
494                                 if(Item_ItemsTime_UpdateTime_Check(it_shield_time, t))
495                                         it_shield_time = t;
496                                 break;
497                         default:
498                                 if(e.weapons & WEPSET_SUPERWEAPONS)
499                                         if(Item_ItemsTime_UpdateTime_Check(it_superweapons_time, t))
500                                                         it_superweapons_time = t;
501                 }
502         }
503         switch(e.items)
504         {
505                 case IT_FUEL_REGEN://"item-fuelregen"
506                         if(Item_ItemsTime_UpdateTime_Check(it_fuelregen_time, t))
507                                 it_fuelregen_time = t;
508                         break;
509                 case IT_JETPACK://"item-jetpack"
510                         if(Item_ItemsTime_UpdateTime_Check(it_jetpack_time, t))
511                                 it_jetpack_time = t;
512                         break;
513         }
514 }
515 void Item_ItemsTime_GetForAll()
516 {
517         entity e;
518         if(warmup_stage)
519         {
520                 FOR_EACH_REALCLIENT(e)
521                         Item_ItemsTime_Get(e);
522         }
523         else
524         {
525                 FOR_EACH_REALCLIENT(e)
526                 {
527                         if (e.classname != "player")
528                                 Item_ItemsTime_Get(e);
529                 }
530         }
531 }
532
533 void Item_Respawn (void)
534 {
535         Item_Show(self, 1);
536         // this is ugly...
537         if(self.items == IT_STRENGTH)
538                 sound (self, CH_TRIGGER, "misc/strength_respawn.wav", VOL_BASE, ATTEN_NORM);    // play respawn sound
539         else if(self.items == IT_INVINCIBLE)
540                 sound (self, CH_TRIGGER, "misc/shield_respawn.wav", VOL_BASE, ATTEN_NORM);      // play respawn sound
541         else
542                 sound (self, CH_TRIGGER, "misc/itemrespawn.wav", VOL_BASE, ATTEN_NORM); // play respawn sound
543         setorigin (self, self.origin);
544
545         if(self.flags & FL_POWERUP || self.classname == "item_armor_large" || self.items == IT_HEALTH || (self.weapons & WEPSET_SUPERWEAPONS))
546         {
547                 Item_ItemsTime_UpdateTime(self, 0);
548                 Item_ItemsTime_GetForAll();
549         }
550
551         self.think = Item_Think;
552         self.nextthink = time;
553
554         //pointparticles(particleeffectnum("item_respawn"), self.origin + self.mins_z * '0 0 1' + '0 0 48', '0 0 0', 1);
555         pointparticles(particleeffectnum("item_respawn"), self.origin + 0.5 * (self.mins + self.maxs), '0 0 0', 1);
556 }
557
558 void Item_RespawnCountdown (void)
559 {
560         if(self.count >= ITEM_RESPAWN_TICKS)
561         {
562                 if(self.waypointsprite_attached)
563                         WaypointSprite_Kill(self.waypointsprite_attached);
564                 Item_Respawn();
565         }
566         else
567         {
568                 self.nextthink = time + 1;
569                 self.count += 1;
570                 if(self.count == 1)
571                 {
572                         string name;
573                         vector rgb = '1 0 1';
574                         name = string_null;
575                         switch(self.items)
576                         {
577                                 case IT_FUEL_REGEN: name = "item-fuelregen"; rgb = '1 0.5 0'; break;
578                                 case IT_JETPACK:    name = "item-jetpack"; rgb = '0.5 0.5 0.5'; break;
579                                 case IT_STRENGTH:   name = "item-strength"; rgb = '0 0 1'; break;
580                                 case IT_INVINCIBLE: name = "item-shield"; rgb = '1 0 1'; break;
581                                 case IT_HEALTH:
582                                         //if (self.classname == "item_health_mega")
583                                                 {name = "item_health_mega"; rgb = '1 0 0';}
584                                         break;
585                                 case IT_ARMOR:
586                                         if (self.classname == "item_armor_large")
587                                                 {name = "item_armor_large"; rgb = '0 1 0';}
588                                         break;
589                         }
590                         item_name = name;
591                         item_color = rgb;
592                         MUTATOR_CALLHOOK(Item_RespawnCountdown);
593                         name = item_name;
594                         rgb = item_color;
595                         if(self.flags & FL_WEAPON)
596                         {
597                                 entity wi = get_weaponinfo(self.weapon);
598                                 if(wi)
599                                 {
600                                         name = wi.wpmodel;
601                                         rgb = '1 0 0';
602                                 }
603                         }
604                         if(name)
605                         {
606                                 WaypointSprite_Spawn(name, 0, 0, self, '0 0 64', world, 0, self, waypointsprite_attached, TRUE, RADARICON_POWERUP, rgb);
607                                 if(self.waypointsprite_attached)
608                                 {
609                                         if (self.items == IT_HEALTH || self.items == IT_ARMOR)
610                                                 WaypointSprite_UpdateRule(self.waypointsprite_attached, 0, SPRITERULE_SPECTATOR);
611                                         WaypointSprite_UpdateBuildFinished(self.waypointsprite_attached, time + ITEM_RESPAWN_TICKS);
612                                 }
613                         }
614                         else
615                         {
616                                 print("Unknown powerup-marked item is wanting to respawn\n");
617                                 localcmd(sprintf("prvm_edict server %d\n", num_for_edict(self)));
618                         }
619                 }
620                 sound (self, CH_TRIGGER, "misc/itemrespawncountdown.wav", VOL_BASE, ATTEN_NORM);        // play respawn sound
621                 if(self.waypointsprite_attached)
622                 {
623                         WaypointSprite_Ping(self.waypointsprite_attached);
624                         //WaypointSprite_UpdateHealth(self.waypointsprite_attached, self.count);
625                 }
626         }
627 }
628
629 void Item_RespawnThink()
630 {
631         self.nextthink = time;
632         if(self.origin != self.oldorigin)
633         {
634                 self.oldorigin = self.origin;
635                 ItemUpdate(self);
636         }
637
638         if(time >= self.wait)
639                 Item_Respawn();
640 }
641
642 void Item_ScheduleRespawnIn(entity e, float t)
643 {
644         if((e.flags & FL_POWERUP) || (e.weapons & WEPSET_SUPERWEAPONS) || e.classname == "item_armor_large" || e.items == IT_HEALTH)
645         {
646                 entity head;
647                 e.think = Item_RespawnCountdown;
648                 e.nextthink = time + max(0, t - ITEM_RESPAWN_TICKS);
649                 e.scheduledrespawntime = e.nextthink + ITEM_RESPAWN_TICKS;
650                 e.count = 0;
651                 if(e.weapons & WEPSET_SUPERWEAPONS)
652                 {
653                         for(t = e.scheduledrespawntime, head = world; (head = nextent(head)); )
654                         {
655                                 if(e == head)
656                                         continue;
657                                 if(clienttype(head) == CLIENTTYPE_NOTACLIENT)
658                                 if(head.weapons & WEPSET_SUPERWEAPONS)
659                                 if(head.classname != "weapon_info")
660                                 {
661                                         if(head.scheduledrespawntime <= time)
662                                         {
663                                                 t = 0;
664                                                 break;
665                                         }
666                                         if(head.scheduledrespawntime < t)
667                                                 t = head.scheduledrespawntime;
668                                 }
669                         }
670                 }
671                 else
672                 {
673                         for(t = e.scheduledrespawntime, head = world; (head = find(head, classname, e.classname)); )
674                         {
675                                 // in instagib .classname is "instagib" for every item
676                                 if(e == head || (g_instagib && e.items != head.items))
677                                         continue;
678                                 if(head.scheduledrespawntime <= time)
679                                 {
680                                         t = 0;
681                                         break;
682                                 }
683                                 if(head.scheduledrespawntime < t)
684                                         t = head.scheduledrespawntime;
685                         }
686                 }
687                 Item_ItemsTime_UpdateTime(e, t);
688                 Item_ItemsTime_GetForAll();
689         }
690         else
691         {
692                 e.think = Item_RespawnThink;
693                 e.nextthink = time;
694                 e.scheduledrespawntime = time + t;
695                 e.wait = time + t;
696         }
697 }
698
699 void Item_ScheduleRespawn(entity e)
700 {
701         if(e.respawntime > 0)
702         {
703                 Item_Show(e, 0);
704                 Item_ScheduleRespawnIn(e, ITEM_RESPAWNTIME(e));
705         }
706         else // if respawntime is -1, this item does not respawn
707                 Item_Show(e, -1);
708 }
709
710 void Item_ScheduleInitialRespawn(entity e)
711 {
712         Item_Show(e, 0);
713         Item_ScheduleRespawnIn(e, game_starttime - time + ITEM_RESPAWNTIME_INITIAL(e));
714 }
715
716 float Item_GiveAmmoTo(entity item, entity player, .float ammotype, float ammomax, float mode)
717 {
718         if (!item.ammotype)
719                 return FALSE;
720
721         if (item.spawnshieldtime)
722         {
723                 if ((player.ammotype < ammomax) || item.pickup_anyway)
724                 {
725                         player.ammotype = bound(player.ammotype, ammomax, player.ammotype + item.ammotype);
726                         goto YEAH;
727                 }
728         }
729         else if(g_weapon_stay == 2)
730         {
731                 float mi = min(item.ammotype, ammomax);
732                 if (player.ammotype < mi)
733                 {
734                         player.ammotype = mi;
735                         goto YEAH;
736                 }
737         }
738
739         return FALSE;
740
741 :YEAH
742         switch(mode)
743         {
744                 case ITEM_MODE_FUEL:
745                         player.pauserotfuel_finished = max(player.pauserotfuel_finished, time + autocvar_g_balance_pause_fuel_rot);
746                         break;
747                 case ITEM_MODE_HEALTH:
748                         player.pauserothealth_finished = max(player.pauserothealth_finished, time + autocvar_g_balance_pause_health_rot);
749                         break;
750                 case ITEM_MODE_ARMOR:
751                         player.pauserotarmor_finished = max(player.pauserotarmor_finished, time + autocvar_g_balance_pause_armor_rot);
752                         break;
753                 default:
754                         break;
755         }
756         return TRUE;
757 }
758
759 float Item_GiveTo(entity item, entity player)
760 {
761         float _switchweapon;
762         float pickedup;
763         float it;
764         float i;
765
766         // if nothing happens to player, just return without taking the item
767         pickedup = FALSE;
768         _switchweapon = FALSE;
769         // in case the player has autoswitch enabled do the following:
770         // if the player is using their best weapon before items are given, they
771         // probably want to switch to an even better weapon after items are given
772         if (player.autoswitch)
773         if (player.switchweapon == w_getbestweapon(player))
774                 _switchweapon = TRUE;
775
776         if (!(player.weapons & WepSet_FromWeapon(player.switchweapon)))
777                 _switchweapon = TRUE;
778
779         pickedup |= Item_GiveAmmoTo(item, player, ammo_fuel, g_pickup_fuel_max, ITEM_MODE_FUEL);
780         pickedup |= Item_GiveAmmoTo(item, player, ammo_shells, g_pickup_shells_max, ITEM_MODE_NONE);
781         pickedup |= Item_GiveAmmoTo(item, player, ammo_nails, g_pickup_nails_max, ITEM_MODE_NONE);
782         pickedup |= Item_GiveAmmoTo(item, player, ammo_rockets, g_pickup_rockets_max, ITEM_MODE_NONE);
783         pickedup |= Item_GiveAmmoTo(item, player, ammo_cells, g_pickup_cells_max, ITEM_MODE_NONE);
784         pickedup |= Item_GiveAmmoTo(item, player, ammo_plasma, g_pickup_plasma_max, ITEM_MODE_NONE);
785         pickedup |= Item_GiveAmmoTo(item, player, health, item.max_health, ITEM_MODE_HEALTH);
786         pickedup |= Item_GiveAmmoTo(item, player, armorvalue, item.max_armorvalue, ITEM_MODE_ARMOR);
787
788         if (item.flags & FL_WEAPON)
789         {
790                 WepSet it;
791                 it = item.weapons;
792                 it &= ~player.weapons;
793
794                 if (it || (item.spawnshieldtime && item.pickup_anyway))
795                 {
796                         pickedup = TRUE;
797                         for(i = WEP_FIRST; i <= WEP_LAST; ++i)
798                         if(it & WepSet_FromWeapon(i))
799                         {
800                                 W_DropEvent(WR_PICKUP, player, i, item);
801                                 W_GiveWeapon(player, i);
802                         }
803                 }
804         }
805
806         if((it = (item.items - (item.items & player.items)) & IT_PICKUPMASK))
807         {
808                 pickedup = TRUE;
809                 player.items |= it;
810                 Send_Notification(NOTIF_ONE, player, MSG_INFO, INFO_ITEM_WEAPON_GOT, item.netname);
811         }
812
813         if (item.strength_finished)
814         {
815                 pickedup = TRUE;
816                 player.strength_finished = max(player.strength_finished, time) + item.strength_finished;
817         }
818         if (item.invincible_finished)
819         {
820                 pickedup = TRUE;
821                 player.invincible_finished = max(player.invincible_finished, time) + item.invincible_finished;
822         }
823         if (item.superweapons_finished)
824         {
825                 pickedup = TRUE;
826                 player.superweapons_finished = max(player.superweapons_finished, time) + item.superweapons_finished;
827         }
828
829 :skip
830
831         // always eat teamed entities
832         if(item.team)
833                 pickedup = TRUE;
834
835         if (!pickedup)
836                 return 0;
837
838         if (_switchweapon)
839                 if (player.switchweapon != w_getbestweapon(player))
840                         W_SwitchWeapon_Force(player, w_getbestweapon(player));
841
842         return 1;
843 }
844
845 void Item_Touch (void)
846 {
847         entity e, head;
848
849         // remove the item if it's currnetly in a NODROP brush or hits a NOIMPACT surface (such as sky)
850         if(self.classname == "droppedweapon")
851         {
852                 if (ITEM_TOUCH_NEEDKILL())
853                 {
854                         remove(self);
855                         return;
856                 }
857         }
858
859         if (!IS_PLAYER(other))
860                 return;
861         if (other.frozen)
862                 return;
863         if (other.deadflag)
864                 return;
865         if (self.solid != SOLID_TRIGGER)
866                 return;
867         if (self.owner == other)
868                 return;
869         if (time < self.item_spawnshieldtime)
870                 return;
871
872         switch(MUTATOR_CALLHOOK(ItemTouch))
873         {
874                 case MUT_ITEMTOUCH_RETURN: { return; }
875                 case MUT_ITEMTOUCH_PICKUP: { goto pickup; }
876         }
877
878         if (self.classname == "droppedweapon")
879         {
880                 self.strength_finished = max(0, self.strength_finished - time);
881                 self.invincible_finished = max(0, self.invincible_finished - time);
882                 self.superweapons_finished = max(0, self.superweapons_finished - time);
883         }
884
885         if(!Item_GiveTo(self, other))
886         {
887                 if (self.classname == "droppedweapon")
888                 {
889                         // undo what we did above
890                         self.strength_finished += time;
891                         self.invincible_finished += time;
892                         self.superweapons_finished += time;
893                 }
894                 return;
895         }
896
897         :pickup
898
899         other.last_pickup = time;
900
901         pointparticles(particleeffectnum("item_pickup"), self.origin, '0 0 0', 1);
902         sound (other, CH_TRIGGER, self.item_pickupsound, VOL_BASE, ATTEN_NORM);
903
904         if (self.classname == "droppedweapon")
905                 remove (self);
906         else if (!self.spawnshieldtime)
907                 return;
908         else
909         {
910                 if(self.team)
911                 {
912                         RandomSelection_Init();
913                         for(head = world; (head = findfloat(head, team, self.team)); )
914                         {
915                                 if(head.flags & FL_ITEM)
916                                 {
917                                         Item_Show(head, -1);
918                                         RandomSelection_Add(head, 0, string_null, head.cnt, 0);
919                                 }
920                         }
921                         e = RandomSelection_chosen_ent;
922
923                 }
924                 else
925                         e = self;
926                 Item_ScheduleRespawn(e);
927         }
928 }
929
930 void Item_Reset()
931 {
932         Item_Show(self, !self.state);
933         setorigin (self, self.origin);
934
935         if(self.classname != "droppedweapon")
936         {
937                 self.think = Item_Think;
938                 self.nextthink = time;
939
940                 if(self.waypointsprite_attached)
941                         WaypointSprite_Kill(self.waypointsprite_attached);
942
943                 if((self.flags & FL_POWERUP) || (self.weapons & WEPSET_SUPERWEAPONS)) // do not spawn powerups initially!
944                         Item_ScheduleInitialRespawn(self);
945         }
946 }
947
948 void Item_FindTeam()
949 {
950         entity head, e;
951
952         if(self.effects & EF_NODRAW)
953         {
954                 // marker for item team search
955                 dprint("Initializing item team ", ftos(self.team), "\n");
956                 RandomSelection_Init();
957                 for(head = world; (head = findfloat(head, team, self.team)); ) if(head.flags & FL_ITEM)
958                         RandomSelection_Add(head, 0, string_null, head.cnt, 0);
959                 e = RandomSelection_chosen_ent;
960                 e.state = 0;
961                 Item_Show(e, 1);
962
963                 for(head = world; (head = findfloat(head, team, self.team)); ) if(head.flags & FL_ITEM)
964                 {
965                         if(head != e)
966                         {
967                                 // make it a non-spawned item
968                                 Item_Show(head, -1);
969                                 head.state = 1; // state 1 = initially hidden item
970                         }
971                         head.effects &= ~EF_NODRAW;
972                 }
973
974                 Item_Reset();
975         }
976 }
977
978 // Savage: used for item garbage-collection
979 // TODO: perhaps nice special effect?
980 void RemoveItem(void)
981 {
982         remove(self);
983 }
984
985 // pickup evaluation functions
986 // these functions decide how desirable an item is to the bots
987
988 float generic_pickupevalfunc(entity player, entity item) {return item.bot_pickupbasevalue;}
989
990 float weapon_pickupevalfunc(entity player, entity item)
991 {
992         float c, j, position;
993
994         // See if I have it already
995         if(item.weapons & ~player.weapons)
996         {
997                 // If I can pick it up
998                 if(!item.spawnshieldtime)
999                         c = 0;
1000                 else if(player.ammo_cells || player.ammo_shells || player.ammo_plasma || player.ammo_nails || player.ammo_rockets)
1001                 {
1002                         // Skilled bots will grab more
1003                         c = bound(0, skill / 10, 1) * 0.5;
1004                 }
1005                 else
1006                         c = 0;
1007         }
1008         else
1009                 c = 1;
1010
1011         // If custom weapon priorities for bots is enabled rate most wanted weapons higher
1012         if( bot_custom_weapon && c )
1013         {
1014                 // Find the highest position on any range
1015                 position = -1;
1016                 for(j = 0; j < WEP_LAST ; ++j){
1017                         if(
1018                                         bot_weapons_far[j] == item.weapon ||
1019                                         bot_weapons_mid[j] == item.weapon ||
1020                                         bot_weapons_close[j] == item.weapon
1021                           )
1022                         {
1023                                 position = j;
1024                                 break;
1025                         }
1026                 }
1027
1028                 // Rate it
1029                 if (position >= 0 )
1030                 {
1031                         position = WEP_LAST - position;
1032                         // item.bot_pickupbasevalue is overwritten here
1033                         return (BOT_PICKUP_RATING_LOW + ( (BOT_PICKUP_RATING_HIGH - BOT_PICKUP_RATING_LOW) * (position / WEP_LAST ))) * c;
1034                 }
1035         }
1036
1037         return item.bot_pickupbasevalue * c;
1038 }
1039
1040 float commodity_pickupevalfunc(entity player, entity item)
1041 {
1042         float c, i;
1043         float need_shells = FALSE, need_nails = FALSE, need_rockets = FALSE, need_cells = FALSE, need_plasma = FALSE, need_fuel = FALSE;
1044         entity wi;
1045         c = 0;
1046
1047         // Detect needed ammo
1048         for(i = WEP_FIRST; i <= WEP_LAST ; ++i)
1049         {
1050                 wi = get_weaponinfo(i);
1051
1052                 if (!(player.weapons & WepSet_FromWeapon(i)))
1053                         continue;
1054
1055                 if(wi.items & IT_SHELLS)
1056                         need_shells = TRUE;
1057                 else if(wi.items & IT_NAILS)
1058                         need_nails = TRUE;
1059                 else if(wi.items & IT_ROCKETS)
1060                         need_rockets = TRUE;
1061                 else if(wi.items & IT_CELLS)
1062                         need_cells = TRUE;
1063                 else if(wi.items & IT_PLASMA)
1064                         need_plasma = TRUE;
1065                 else if(wi.items & IT_FUEL)
1066                         need_fuel = TRUE;
1067         }
1068
1069         // TODO: figure out if the player even has the weapon this ammo is for?
1070         // may not affect strategy much though...
1071         // find out how much more ammo/armor/health the player can hold
1072         if (need_shells)
1073         if (item.ammo_shells)
1074         if (player.ammo_shells < g_pickup_shells_max)
1075                 c = c + max(0, 1 - player.ammo_shells / g_pickup_shells_max);
1076         if (need_nails)
1077         if (item.ammo_nails)
1078         if (player.ammo_nails < g_pickup_nails_max)
1079                 c = c + max(0, 1 - player.ammo_nails / g_pickup_nails_max);
1080         if (need_rockets)
1081         if (item.ammo_rockets)
1082         if (player.ammo_rockets < g_pickup_rockets_max)
1083                 c = c + max(0, 1 - player.ammo_rockets / g_pickup_rockets_max);
1084         if (need_cells)
1085         if (item.ammo_cells)
1086         if (player.ammo_cells < g_pickup_cells_max)
1087                 c = c + max(0, 1 - player.ammo_cells / g_pickup_cells_max);
1088         if (need_plasma)
1089         if (item.ammo_plasma)
1090         if (player.ammo_plasma < g_pickup_plasma_max)
1091                 c = c + max(0, 1 - player.ammo_plasma / g_pickup_plasma_max);
1092         if (need_fuel)
1093         if (item.ammo_fuel)
1094         if (player.ammo_fuel < g_pickup_fuel_max)
1095                 c = c + max(0, 1 - player.ammo_fuel / g_pickup_fuel_max);
1096         if (item.armorvalue)
1097         if (player.armorvalue < item.max_armorvalue)
1098                 c = c + max(0, 1 - player.armorvalue / item.max_armorvalue);
1099         if (item.health)
1100         if (player.health < item.max_health)
1101                 c = c + max(0, 1 - player.health / item.max_health);
1102
1103         return item.bot_pickupbasevalue * c;
1104 }
1105
1106 void Item_Damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
1107 {
1108         if(ITEM_DAMAGE_NEEDKILL(deathtype))
1109                 RemoveItem();
1110 }
1111
1112 void StartItem (string itemmodel, string pickupsound, float defaultrespawntime, float defaultrespawntimejitter, string itemname, float itemid, float weaponid, float itemflags, float(entity player, entity item) pickupevalfunc, float pickupbasevalue)
1113 {
1114         startitem_failed = FALSE;
1115
1116         if(self.model == "")
1117                 self.model = itemmodel;
1118
1119         if(self.model == "")
1120     {
1121         error(strcat("^1Tried to spawn ", itemname, " with no model!\n"));
1122         return;
1123     }
1124
1125         if(self.item_pickupsound == "")
1126                 self.item_pickupsound = pickupsound;
1127
1128         if(!self.respawntime) // both need to be set
1129         {
1130                 self.respawntime = defaultrespawntime;
1131                 self.respawntimejitter = defaultrespawntimejitter;
1132         }
1133
1134         self.items = itemid;
1135         self.weapon = weaponid;
1136
1137         if(weaponid)
1138                 self.weapons = WepSet_FromWeapon(weaponid);
1139
1140         self.flags = FL_ITEM | itemflags;
1141
1142         if(MUTATOR_CALLHOOK(FilterItem)) // error means we do not want the item
1143         {
1144                 startitem_failed = TRUE;
1145                 remove(self);
1146                 return;
1147         }
1148
1149         // is it a dropped weapon?
1150         if (self.classname == "droppedweapon")
1151         {
1152                 self.reset = SUB_Remove;
1153                 // it's a dropped weapon
1154                 self.movetype = MOVETYPE_TOSS;
1155
1156                 // Savage: remove thrown items after a certain period of time ("garbage collection")
1157                 self.think = RemoveItem;
1158                 self.nextthink = time + 20;
1159
1160                 self.takedamage = DAMAGE_YES;
1161                 self.event_damage = Item_Damage;
1162
1163                 if(self.strength_finished || self.invincible_finished || self.superweapons_finished)
1164                 /*
1165                 if(self.items == 0)
1166                 if(!(self.weapons & ~WEPSET_SUPERWEAPONS)) // only superweapons
1167                 if(self.ammo_nails == 0)
1168                 if(self.ammo_cells == 0)
1169                 if(self.ammo_rockets == 0)
1170                 if(self.ammo_shells == 0)
1171                 if(self.ammo_fuel == 0)
1172                 if(self.health == 0)
1173                 if(self.armorvalue == 0)
1174                 */
1175                 {
1176                         // if item is worthless after a timer, have it expire then
1177                         self.nextthink = max(self.strength_finished, self.invincible_finished, self.superweapons_finished);
1178                 }
1179
1180                 // don't drop if in a NODROP zone (such as lava)
1181                 traceline(self.origin, self.origin, MOVE_NORMAL, self);
1182                 if (trace_dpstartcontents & DPCONTENTS_NODROP)
1183                 {
1184                         startitem_failed = TRUE;
1185                         remove(self);
1186                         return;
1187                 }
1188         }
1189         else
1190         {
1191                 if(!have_pickup_item())
1192                 {
1193                         startitem_failed = TRUE;
1194                         remove (self);
1195                         return;
1196                 }
1197
1198                 self.reset = Item_Reset;
1199                 // it's a level item
1200                 if(self.spawnflags & 1)
1201                         self.noalign = 1;
1202                 if (self.noalign)
1203                         self.movetype = MOVETYPE_NONE;
1204                 else
1205                         self.movetype = MOVETYPE_TOSS;
1206                 // do item filtering according to game mode and other things
1207                 if (!self.noalign)
1208                 {
1209                         // first nudge it off the floor a little bit to avoid math errors
1210                         setorigin(self, self.origin + '0 0 1');
1211                         // set item size before we spawn a spawnfunc_waypoint
1212                         if((itemflags & FL_POWERUP) || self.health || self.armorvalue)
1213                                 setsize (self, '-16 -16 0', '16 16 48');
1214                         else
1215                                 setsize (self, '-16 -16 0', '16 16 32');
1216
1217                         // note droptofloor returns FALSE if stuck/or would fall too far
1218                         droptofloor();
1219                         waypoint_spawnforitem(self);
1220                 }
1221
1222                 /*
1223                  * can't do it that way, as it would break maps
1224                  * TODO make a target_give like entity another way, that perhaps has
1225                  * the weapon name in a key
1226                 if(self.targetname)
1227                 {
1228                         // target_give not yet supported; maybe later
1229                         print("removed targeted ", self.classname, "\n");
1230                         startitem_failed = TRUE;
1231                         remove (self);
1232                         return;
1233                 }
1234                 */
1235
1236                 if(autocvar_spawn_debug >= 2)
1237                 {
1238                         entity otheritem;
1239                         for(otheritem = findradius(self.origin, 3); otheritem; otheritem = otheritem.chain)
1240                         {
1241                             // why not flags & fl_item?
1242                                 if(otheritem.is_item)
1243                                 {
1244                                         dprint("XXX Found duplicated item: ", itemname, vtos(self.origin));
1245                                         dprint(" vs ", otheritem.netname, vtos(otheritem.origin), "\n");
1246                                         error("Mapper sucks.");
1247                                 }
1248                         }
1249                         self.is_item = TRUE;
1250                 }
1251
1252                 weaponsInMap |= WepSet_FromWeapon(weaponid);
1253
1254                 precache_model (self.model);
1255                 precache_sound (self.item_pickupsound);
1256
1257                 precache_sound ("misc/itemrespawncountdown.wav");
1258                 if(itemid == IT_STRENGTH)
1259                         precache_sound ("misc/strength_respawn.wav");
1260                 else if(itemid == IT_INVINCIBLE)
1261                         precache_sound ("misc/shield_respawn.wav");
1262                 else
1263                         precache_sound ("misc/itemrespawn.wav");
1264
1265                 if((itemflags & (FL_POWERUP | FL_WEAPON)) || (itemid & (IT_HEALTH | IT_ARMOR | IT_KEY1 | IT_KEY2)))
1266                         self.target = "###item###"; // for finding the nearest item using find()
1267
1268                 Item_ItemsTime_UpdateTime(self, 0);
1269         }
1270
1271         self.bot_pickup = TRUE;
1272         self.bot_pickupevalfunc = pickupevalfunc;
1273         self.bot_pickupbasevalue = pickupbasevalue;
1274         self.mdl = self.model;
1275         self.netname = itemname;
1276         self.touch = Item_Touch;
1277         setmodel(self, "null"); // precision set below
1278         //self.effects |= EF_LOWPRECISION;
1279
1280         if((itemflags & FL_POWERUP) || self.health || self.armorvalue)
1281     {
1282         self.pos1 = '-16 -16 0';
1283         self.pos2 = '16 16 48';
1284     }
1285         else
1286     {
1287         self.pos1 = '-16 -16 0';
1288         self.pos2 = '16 16 32';
1289     }
1290     setsize (self, self.pos1, self.pos2);
1291
1292     if(itemflags & FL_POWERUP)
1293         self.ItemStatus |= ITS_ANIMATE1;
1294
1295         if(self.armorvalue || self.health)
1296         self.ItemStatus |= ITS_ANIMATE2;
1297
1298         if(itemflags & FL_WEAPON)
1299         {
1300                 if (self.classname != "droppedweapon") // if dropped, colormap is already set up nicely
1301             self.colormap = 1024; // color shirt=0 pants=0 grey
1302         else
1303             self.gravity = 1;
1304
1305                 self.ItemStatus |= ITS_ANIMATE1;
1306                 self.ItemStatus |= ISF_COLORMAP;
1307         }
1308
1309         self.state = 0;
1310         if(self.team) // broken, no idea why.
1311         {
1312                 if(!self.cnt)
1313                         self.cnt = 1; // item probability weight
1314
1315                 self.effects |= EF_NODRAW; // marker for item team search
1316                 InitializeEntity(self, Item_FindTeam, INITPRIO_FINDTARGET);
1317         }
1318         else
1319                 Item_Reset();
1320
1321     Net_LinkEntity(self, FALSE, 0, ItemSend);
1322         
1323         self.SendFlags |= ISF_SIZE;
1324         if(self.angles)
1325                 self.SendFlags |= ISF_ANGLES;
1326
1327         // call this hook after everything else has been done
1328         if(MUTATOR_CALLHOOK(Item_Spawn))
1329         {
1330                 startitem_failed = TRUE;
1331                 remove(self);
1332                 return;
1333         }
1334 }
1335 void spawnfunc_item_rockets (void) {
1336         if(!self.ammo_rockets)
1337                 self.ammo_rockets = g_pickup_rockets;
1338         if(!self.pickup_anyway)
1339                 self.pickup_anyway = g_pickup_ammo_anyway;
1340         StartItem ("models/items/a_rockets.md3", "misc/itempickup.wav", g_pickup_respawntime_ammo, g_pickup_respawntimejitter_ammo, "rockets", IT_ROCKETS, 0, 0, commodity_pickupevalfunc, 3000);
1341 }
1342
1343 void spawnfunc_item_shells (void);
1344 void spawnfunc_item_bullets (void) {
1345         if(!weaponswapping)
1346         if(autocvar_sv_q3acompat_machineshotgunswap)
1347         if(self.classname != "droppedweapon")
1348         {
1349                 weaponswapping = TRUE;
1350                 spawnfunc_item_shells();
1351                 weaponswapping = FALSE;
1352                 return;
1353         }
1354
1355         if(!self.ammo_nails)
1356                 self.ammo_nails = g_pickup_nails;
1357         if(!self.pickup_anyway)
1358                 self.pickup_anyway = g_pickup_ammo_anyway;
1359         StartItem ("models/items/a_bullets.mdl", "misc/itempickup.wav", g_pickup_respawntime_ammo, g_pickup_respawntimejitter_ammo, "bullets", IT_NAILS, 0, 0, commodity_pickupevalfunc, 2000);
1360 }
1361
1362 void spawnfunc_item_cells (void) {
1363         if(!self.ammo_cells)
1364                 self.ammo_cells = g_pickup_cells;
1365         if(!self.pickup_anyway)
1366                 self.pickup_anyway = g_pickup_ammo_anyway;
1367         StartItem ("models/items/a_cells.md3", "misc/itempickup.wav", g_pickup_respawntime_ammo, g_pickup_respawntimejitter_ammo, "cells", IT_CELLS, 0, 0, commodity_pickupevalfunc, 2000);
1368 }
1369
1370 void spawnfunc_item_plasma()
1371 {
1372         if(!self.ammo_plasma)
1373                 self.ammo_plasma = g_pickup_plasma;
1374         if(!self.pickup_anyway)
1375                 self.pickup_anyway = g_pickup_ammo_anyway;
1376         StartItem ("models/items/a_cells.md3", "misc/itempickup.wav", g_pickup_respawntime_ammo, g_pickup_respawntimejitter_ammo, "plasma", IT_PLASMA, 0, 0, commodity_pickupevalfunc, 2000);
1377 }
1378
1379 void spawnfunc_item_shells (void) {
1380         if(!weaponswapping)
1381         if(autocvar_sv_q3acompat_machineshotgunswap)
1382         if(self.classname != "droppedweapon")
1383         {
1384                 weaponswapping = TRUE;
1385                 spawnfunc_item_bullets();
1386                 weaponswapping = FALSE;
1387                 return;
1388         }
1389
1390         if(!self.ammo_shells)
1391                 self.ammo_shells = g_pickup_shells;
1392         if(!self.pickup_anyway)
1393                 self.pickup_anyway = g_pickup_ammo_anyway;
1394         StartItem ("models/items/a_shells.md3", "misc/itempickup.wav", g_pickup_respawntime_ammo, g_pickup_respawntimejitter_ammo, "shells", IT_SHELLS, 0, 0, commodity_pickupevalfunc, 500);
1395 }
1396
1397 void spawnfunc_item_armor_small (void) {
1398         if(!self.armorvalue)
1399                 self.armorvalue = g_pickup_armorsmall;
1400         if(!self.max_armorvalue)
1401                 self.max_armorvalue = g_pickup_armorsmall_max;
1402         if(!self.pickup_anyway)
1403                 self.pickup_anyway = g_pickup_armorsmall_anyway;
1404         StartItem ("models/items/item_armor_small.md3", "misc/armor1.wav", g_pickup_respawntime_short, g_pickup_respawntimejitter_short, "5 Armor", IT_ARMOR_SHARD, 0, 0, commodity_pickupevalfunc, BOT_PICKUP_RATING_LOW);
1405 }
1406
1407 void spawnfunc_item_armor_medium (void) {
1408         if(!self.armorvalue)
1409                 self.armorvalue = g_pickup_armormedium;
1410         if(!self.max_armorvalue)
1411                 self.max_armorvalue = g_pickup_armormedium_max;
1412         if(!self.pickup_anyway)
1413                 self.pickup_anyway = g_pickup_armormedium_anyway;
1414         StartItem ("models/items/item_armor_medium.md3", "misc/armor10.wav", g_pickup_respawntime_medium, g_pickup_respawntimejitter_medium, "25 Armor", IT_ARMOR, 0, 0, commodity_pickupevalfunc, BOT_PICKUP_RATING_MID);
1415 }
1416
1417 void spawnfunc_item_armor_big (void) {
1418         if(!self.armorvalue)
1419                 self.armorvalue = g_pickup_armorbig;
1420         if(!self.max_armorvalue)
1421                 self.max_armorvalue = g_pickup_armorbig_max;
1422         if(!self.pickup_anyway)
1423                 self.pickup_anyway = g_pickup_armorbig_anyway;
1424         StartItem ("models/items/item_armor_big.md3", "misc/armor17_5.wav", g_pickup_respawntime_long, g_pickup_respawntimejitter_long, "50 Armor", IT_ARMOR, 0, 0, commodity_pickupevalfunc, 20000);
1425 }
1426
1427 void spawnfunc_item_armor_large (void) {
1428         if(!self.armorvalue)
1429                 self.armorvalue = g_pickup_armorlarge;
1430         if(!self.max_armorvalue)
1431                 self.max_armorvalue = g_pickup_armorlarge_max;
1432         if(!self.pickup_anyway)
1433                 self.pickup_anyway = g_pickup_armorlarge_anyway;
1434         StartItem ("models/items/item_armor_large.md3", "misc/armor25.wav", g_pickup_respawntime_long, g_pickup_respawntimejitter_long, "100 Armor", IT_ARMOR, 0, 0, commodity_pickupevalfunc, BOT_PICKUP_RATING_HIGH);
1435 }
1436
1437 void spawnfunc_item_health_small (void) {
1438         if(!self.max_health)
1439                 self.max_health = g_pickup_healthsmall_max;
1440         if(!self.health)
1441                 self.health = g_pickup_healthsmall;
1442         if(!self.pickup_anyway)
1443                 self.pickup_anyway = g_pickup_healthsmall_anyway;
1444         StartItem ("models/items/g_h1.md3", "misc/minihealth.wav", g_pickup_respawntime_short, g_pickup_respawntimejitter_short, "5 Health", IT_5HP, 0, 0, commodity_pickupevalfunc, BOT_PICKUP_RATING_LOW);
1445 }
1446
1447 void spawnfunc_item_health_medium (void) {
1448         if(!self.max_health)
1449                 self.max_health = g_pickup_healthmedium_max;
1450         if(!self.health)
1451                 self.health = g_pickup_healthmedium;
1452         if(!self.pickup_anyway)
1453                 self.pickup_anyway = g_pickup_healthmedium_anyway;
1454         StartItem ("models/items/g_h25.md3", "misc/mediumhealth.wav", g_pickup_respawntime_short, g_pickup_respawntimejitter_short, "25 Health", IT_25HP, 0, 0, commodity_pickupevalfunc, BOT_PICKUP_RATING_MID);
1455 }
1456
1457 void spawnfunc_item_health_large (void) {
1458         if(!self.max_health)
1459                 self.max_health = g_pickup_healthlarge_max;
1460         if(!self.health)
1461                 self.health = g_pickup_healthlarge;
1462         if(!self.pickup_anyway)
1463                 self.pickup_anyway = g_pickup_healthlarge_anyway;
1464         StartItem ("models/items/g_h50.md3", "misc/mediumhealth.wav", g_pickup_respawntime_medium, g_pickup_respawntimejitter_medium, "50 Health", IT_25HP, 0, 0, commodity_pickupevalfunc, BOT_PICKUP_RATING_MID);
1465 }
1466
1467 void spawnfunc_item_health_mega (void) {
1468                 if(!self.max_health)
1469                         self.max_health = g_pickup_healthmega_max;
1470                 if(!self.health)
1471                         self.health = g_pickup_healthmega;
1472                 if(!self.pickup_anyway)
1473                         self.pickup_anyway = g_pickup_healthmega_anyway;
1474                 StartItem ("models/items/g_h100.md3", "misc/megahealth.wav", g_pickup_respawntime_long, g_pickup_respawntimejitter_long, "100 Health", IT_HEALTH, 0, 0, commodity_pickupevalfunc, BOT_PICKUP_RATING_HIGH);
1475 }
1476
1477 // support old misnamed entities
1478 void spawnfunc_item_armor1() { spawnfunc_item_armor_small(); }  // FIXME: in Quake this is green armor, in Xonotic maps it is an armor shard
1479 void spawnfunc_item_armor25() { spawnfunc_item_armor_large(); }
1480 void spawnfunc_item_health1() { spawnfunc_item_health_small(); }
1481 void spawnfunc_item_health25() { spawnfunc_item_health_medium(); }
1482 void spawnfunc_item_health100() { spawnfunc_item_health_mega(); }
1483
1484 void spawnfunc_item_strength (void) {
1485                 precache_sound("weapons/strength_fire.wav");
1486                 if(!self.strength_finished)
1487                         self.strength_finished = autocvar_g_balance_powerup_strength_time;
1488                 StartItem ("models/items/g_strength.md3", "misc/powerup.wav", g_pickup_respawntime_powerup, g_pickup_respawntimejitter_powerup, "Strength Powerup", IT_STRENGTH, 0, FL_POWERUP, generic_pickupevalfunc, 100000);
1489 }
1490
1491 void spawnfunc_item_invincible (void) {
1492                 if(!self.invincible_finished)
1493                         self.invincible_finished = autocvar_g_balance_powerup_invincible_time;
1494                 StartItem ("models/items/g_invincible.md3", "misc/powerup_shield.wav", g_pickup_respawntime_powerup, g_pickup_respawntimejitter_powerup, "Shield", IT_INVINCIBLE, 0, FL_POWERUP, generic_pickupevalfunc, 100000);
1495 }
1496
1497 // compatibility:
1498 void spawnfunc_item_quad (void) {self.classname = "item_strength";spawnfunc_item_strength();}
1499
1500 void target_items_use (void)
1501 {
1502         if(activator.classname == "droppedweapon")
1503         {
1504                 EXACTTRIGGER_TOUCH;
1505                 remove(activator);
1506                 return;
1507         }
1508
1509         if (!IS_PLAYER(activator))
1510                 return;
1511         if(activator.deadflag != DEAD_NO)
1512                 return;
1513         EXACTTRIGGER_TOUCH;
1514
1515         entity e;
1516         for(e = world; (e = find(e, classname, "droppedweapon")); )
1517                 if(e.enemy == activator)
1518                         remove(e);
1519
1520         if(GiveItems(activator, 0, tokenize_console(self.netname)))
1521                 centerprint(activator, self.message);
1522 }
1523
1524 void spawnfunc_target_items (void)
1525 {
1526         float n, i, j;
1527         entity e;
1528
1529         self.use = target_items_use;
1530         if(!self.strength_finished)
1531                 self.strength_finished = autocvar_g_balance_powerup_strength_time;
1532         if(!self.invincible_finished)
1533                 self.invincible_finished = autocvar_g_balance_powerup_invincible_time;
1534         if(!self.superweapons_finished)
1535                 self.superweapons_finished = autocvar_g_balance_superweapons_time;
1536
1537         precache_sound("misc/itempickup.wav");
1538         precache_sound("misc/megahealth.wav");
1539         precache_sound("misc/armor25.wav");
1540         precache_sound("misc/powerup.wav");
1541         precache_sound("misc/poweroff.wav");
1542         precache_sound("weapons/weaponpickup.wav");
1543
1544         n = tokenize_console(self.netname);
1545         if(argv(0) == "give")
1546         {
1547                 self.netname = substring(self.netname, argv_start_index(1), argv_end_index(-1) - argv_start_index(1));
1548         }
1549         else
1550         {
1551                 for(i = 0; i < n; ++i)
1552                 {
1553                         if     (argv(i) == "unlimited_ammo")         self.items |= IT_UNLIMITED_AMMO;
1554                         else if(argv(i) == "unlimited_weapon_ammo")  self.items |= IT_UNLIMITED_WEAPON_AMMO;
1555                         else if(argv(i) == "unlimited_superweapons") self.items |= IT_UNLIMITED_SUPERWEAPONS;
1556                         else if(argv(i) == "strength")               self.items |= IT_STRENGTH;
1557                         else if(argv(i) == "invincible")             self.items |= IT_INVINCIBLE;
1558                         else if(argv(i) == "superweapons")           self.items |= IT_SUPERWEAPON;
1559                         else if(argv(i) == "jetpack")                self.items |= IT_JETPACK;
1560                         else if(argv(i) == "fuel_regen")             self.items |= IT_FUEL_REGEN;
1561                         else
1562                         {
1563                                 for(j = WEP_FIRST; j <= WEP_LAST; ++j)
1564                                 {
1565                                         e = get_weaponinfo(j);
1566                                         if(argv(i) == e.netname)
1567                                         {
1568                                                 self.weapons |= WepSet_FromWeapon(j);
1569                                                 if(self.spawnflags == 0 || self.spawnflags == 2)
1570                                                         WEP_ACTION(e.weapon, WR_INIT);
1571                                                 break;
1572                                         }
1573                                 }
1574                                 if(j > WEP_LAST)
1575                                         print("target_items: invalid item ", argv(i), "\n");
1576                         }
1577                 }
1578
1579                 string itemprefix, valueprefix;
1580                 if(self.spawnflags == 0)
1581                 {
1582                         itemprefix = "";
1583                         valueprefix = "";
1584                 }
1585                 else if(self.spawnflags == 1)
1586                 {
1587                         itemprefix = "max ";
1588                         valueprefix = "max ";
1589                 }
1590                 else if(self.spawnflags == 2)
1591                 {
1592                         itemprefix = "min ";
1593                         valueprefix = "min ";
1594                 }
1595                 else if(self.spawnflags == 4)
1596                 {
1597                         itemprefix = "minus ";
1598                         valueprefix = "max ";
1599                 }
1600                 else
1601                 {
1602                         error("invalid spawnflags");
1603 #ifdef GMQCC
1604                         itemprefix = string_null;
1605                         valueprefix = string_null;
1606 #endif
1607                 }
1608
1609                 self.netname = "";
1610                 self.netname = sprintf("%s %s%d %s", self.netname, itemprefix, !!(self.items & IT_UNLIMITED_WEAPON_AMMO), "unlimited_weapon_ammo");
1611                 self.netname = sprintf("%s %s%d %s", self.netname, itemprefix, !!(self.items & IT_UNLIMITED_SUPERWEAPONS), "unlimited_superweapons");
1612                 self.netname = sprintf("%s %s%d %s", self.netname, valueprefix, self.strength_finished * !!(self.items & IT_STRENGTH), "strength");
1613                 self.netname = sprintf("%s %s%d %s", self.netname, valueprefix, self.invincible_finished * !!(self.items & IT_INVINCIBLE), "invincible");
1614                 self.netname = sprintf("%s %s%d %s", self.netname, valueprefix, self.superweapons_finished * !!(self.items & IT_SUPERWEAPON), "superweapons");
1615                 self.netname = sprintf("%s %s%d %s", self.netname, itemprefix, !!(self.items & IT_JETPACK), "jetpack");
1616                 self.netname = sprintf("%s %s%d %s", self.netname, itemprefix, !!(self.items & IT_FUEL_REGEN), "fuel_regen");
1617                 if(self.ammo_shells != 0) self.netname = sprintf("%s %s%d %s", self.netname, valueprefix, max(0, self.ammo_shells), "shells");
1618                 if(self.ammo_nails != 0) self.netname = sprintf("%s %s%d %s", self.netname, valueprefix, max(0, self.ammo_nails), "nails");
1619                 if(self.ammo_rockets != 0) self.netname = sprintf("%s %s%d %s", self.netname, valueprefix, max(0, self.ammo_rockets), "rockets");
1620                 if(self.ammo_cells != 0) self.netname = sprintf("%s %s%d %s", self.netname, valueprefix, max(0, self.ammo_cells), "cells");
1621                 if(self.ammo_plasma != 0) self.netname = sprintf("%s %s%d %s", self.netname, valueprefix, max(0, self.ammo_plasma), "plasma");
1622                 if(self.ammo_fuel != 0) self.netname = sprintf("%s %s%d %s", self.netname, valueprefix, max(0, self.ammo_fuel), "fuel");
1623                 if(self.health != 0) self.netname = sprintf("%s %s%d %s", self.netname, valueprefix, max(0, self.health), "health");
1624                 if(self.armorvalue != 0) self.netname = sprintf("%s %s%d %s", self.netname, valueprefix, max(0, self.health), "armor");
1625                 for(j = WEP_FIRST; j <= WEP_LAST; ++j)
1626                 {
1627                         e = get_weaponinfo(j);
1628                         if(e.weapon)
1629                                 self.netname = sprintf("%s %s%d %s", self.netname, itemprefix, !!(self.weapons & WepSet_FromWeapon(j)), e.netname);
1630                 }
1631         }
1632         self.netname = strzone(self.netname);
1633         //print(self.netname, "\n");
1634
1635         n = tokenize_console(self.netname);
1636         for(i = 0; i < n; ++i)
1637         {
1638                 for(j = WEP_FIRST; j <= WEP_LAST; ++j)
1639                 {
1640                         e = get_weaponinfo(j);
1641                         if(argv(i) == e.netname)
1642                         {
1643                                 WEP_ACTION(e.weapon, WR_INIT);
1644                                 break;
1645                         }
1646                 }
1647         }
1648 }
1649
1650 void spawnfunc_item_fuel(void)
1651 {
1652         if(!self.ammo_fuel)
1653                 self.ammo_fuel = g_pickup_fuel;
1654         if(!self.pickup_anyway)
1655                 self.pickup_anyway = g_pickup_ammo_anyway;
1656         StartItem ("models/items/g_fuel.md3", "misc/itempickup.wav", g_pickup_respawntime_ammo, g_pickup_respawntimejitter_ammo, "Fuel", IT_FUEL, 0, 0, commodity_pickupevalfunc, BOT_PICKUP_RATING_LOW);
1657 }
1658
1659 void spawnfunc_item_fuel_regen(void)
1660 {
1661         if(start_items & IT_FUEL_REGEN)
1662         {
1663                 spawnfunc_item_fuel();
1664                 return;
1665         }
1666         StartItem ("models/items/g_fuelregen.md3", "misc/itempickup.wav", g_pickup_respawntime_powerup, g_pickup_respawntimejitter_powerup, "Fuel regenerator", IT_FUEL_REGEN, 0, FL_POWERUP, commodity_pickupevalfunc, BOT_PICKUP_RATING_LOW);
1667 }
1668
1669 void spawnfunc_item_jetpack(void)
1670 {
1671         if(!self.ammo_fuel)
1672                 self.ammo_fuel = g_pickup_fuel_jetpack;
1673         if(start_items & IT_JETPACK)
1674         {
1675                 spawnfunc_item_fuel();
1676                 return;
1677         }
1678         StartItem ("models/items/g_jetpack.md3", "misc/itempickup.wav", g_pickup_respawntime_powerup, g_pickup_respawntimejitter_powerup, "Jet pack", IT_JETPACK, 0, FL_POWERUP, commodity_pickupevalfunc, BOT_PICKUP_RATING_LOW);
1679 }
1680
1681 float GiveWeapon(entity e, float wpn, float op, float val)
1682 {
1683         WepSet v0, v1;
1684         v0 = (e.weapons & WepSet_FromWeapon(wpn));
1685         switch(op)
1686         {
1687                 case OP_SET:
1688                         if(val > 0)
1689                                 e.weapons |= WepSet_FromWeapon(wpn);
1690                         else
1691                                 e.weapons &= ~WepSet_FromWeapon(wpn);
1692                         break;
1693                 case OP_MIN:
1694                 case OP_PLUS:
1695                         if(val > 0)
1696                                 e.weapons |= WepSet_FromWeapon(wpn);
1697                         break;
1698                 case OP_MAX:
1699                         if(val <= 0)
1700                                 e.weapons &= ~WepSet_FromWeapon(wpn);
1701                         break;
1702                 case OP_MINUS:
1703                         if(val > 0)
1704                                 e.weapons &= ~WepSet_FromWeapon(wpn);
1705                         break;
1706         }
1707         v1 = (e.weapons & WepSet_FromWeapon(wpn));
1708         return (v0 != v1);
1709 }
1710
1711 float GiveBit(entity e, .float fld, float bit, float op, float val)
1712 {
1713         float v0, v1;
1714         v0 = (e.fld & bit);
1715         switch(op)
1716         {
1717                 case OP_SET:
1718                         if(val > 0)
1719                                 e.fld |= bit;
1720                         else
1721                                 e.fld &= ~bit;
1722                         break;
1723                 case OP_MIN:
1724                 case OP_PLUS:
1725                         if(val > 0)
1726                                 e.fld |= bit;
1727                         break;
1728                 case OP_MAX:
1729                         if(val <= 0)
1730                                 e.fld &= ~bit;
1731                         break;
1732                 case OP_MINUS:
1733                         if(val > 0)
1734                                 e.fld &= ~bit;
1735                         break;
1736         }
1737         v1 = (e.fld & bit);
1738         return (v0 != v1);
1739 }
1740
1741 float GiveValue(entity e, .float fld, float op, float val)
1742 {
1743         float v0, v1;
1744         v0 = e.fld;
1745         switch(op)
1746         {
1747                 case OP_SET:
1748                         e.fld = val;
1749                         break;
1750                 case OP_MIN:
1751                         e.fld = max(e.fld, val); // min 100 cells = at least 100 cells
1752                         break;
1753                 case OP_MAX:
1754                         e.fld = min(e.fld, val);
1755                         break;
1756                 case OP_PLUS:
1757                         e.fld += val;
1758                         break;
1759                 case OP_MINUS:
1760                         e.fld -= val;
1761                         break;
1762         }
1763         v1 = e.fld;
1764         return (v0 != v1);
1765 }
1766
1767 void GiveSound(entity e, float v0, float v1, float t, string snd_incr, string snd_decr)
1768 {
1769         if(v1 == v0)
1770                 return;
1771         if(v1 <= v0 - t)
1772         {
1773                 if(snd_decr != "")
1774                         sound (e, CH_TRIGGER, snd_decr, VOL_BASE, ATTEN_NORM);
1775         }
1776         else if(v0 >= v0 + t)
1777         {
1778                 if(snd_incr != "")
1779                         sound (e, CH_TRIGGER, snd_incr, VOL_BASE, ATTEN_NORM);
1780         }
1781 }
1782
1783 void GiveRot(entity e, float v0, float v1, .float rotfield, float rottime, .float regenfield, float regentime)
1784 {
1785         if(v0 < v1)
1786                 e.rotfield = max(e.rotfield, time + rottime);
1787         else if(v0 > v1)
1788                 e.regenfield = max(e.regenfield, time + regentime);
1789 }
1790 float GiveItems(entity e, float beginarg, float endarg)
1791 {
1792         float got, i, j, val, op;
1793         float _switchweapon;
1794         entity wi;
1795         string cmd;
1796
1797         val = 999;
1798         op = OP_SET;
1799
1800         got = 0;
1801
1802         _switchweapon = FALSE;
1803         if (e.autoswitch)
1804                 if (e.switchweapon == w_getbestweapon(e))
1805                         _switchweapon = TRUE;
1806
1807         e.strength_finished = max(0, e.strength_finished - time);
1808         e.invincible_finished = max(0, e.invincible_finished - time);
1809         e.superweapons_finished = max(0, e.superweapons_finished - time);
1810
1811         PREGIVE(e, items);
1812         PREGIVE_WEAPONS(e);
1813         PREGIVE(e, strength_finished);
1814         PREGIVE(e, invincible_finished);
1815         PREGIVE(e, superweapons_finished);
1816         PREGIVE(e, ammo_nails);
1817         PREGIVE(e, ammo_cells);
1818         PREGIVE(e, ammo_plasma);
1819         PREGIVE(e, ammo_shells);
1820         PREGIVE(e, ammo_rockets);
1821         PREGIVE(e, ammo_fuel);
1822         PREGIVE(e, armorvalue);
1823         PREGIVE(e, health);
1824
1825         for(i = beginarg; i < endarg; ++i)
1826         {
1827                 cmd = argv(i);
1828
1829                 if(cmd == "0" || stof(cmd))
1830                 {
1831                         val = stof(cmd);
1832                         continue;
1833                 }
1834                 switch(cmd)
1835                 {
1836                         case "no":
1837                                 op = OP_MAX;
1838                                 val = 0;
1839                                 continue;
1840                         case "max":
1841                                 op = OP_MAX;
1842                                 continue;
1843                         case "min":
1844                                 op = OP_MIN;
1845                                 continue;
1846                         case "plus":
1847                                 op = OP_PLUS;
1848                                 continue;
1849                         case "minus":
1850                                 op = OP_MINUS;
1851                                 continue;
1852                         case "ALL":
1853                                 got += GiveBit(e, items, IT_FUEL_REGEN, op, val);
1854                                 got += GiveValue(e, strength_finished, op, val);
1855                                 got += GiveValue(e, invincible_finished, op, val);
1856                                 got += GiveValue(e, superweapons_finished, op, val);
1857                                 got += GiveBit(e, items, IT_UNLIMITED_AMMO, op, val);
1858                         case "all":
1859                                 got += GiveBit(e, items, IT_JETPACK, op, val);
1860                                 got += GiveValue(e, health, op, val);
1861                                 got += GiveValue(e, armorvalue, op, val);
1862                         case "allweapons":
1863                                 for(j = WEP_FIRST; j <= WEP_LAST; ++j)
1864                                 {
1865                                         wi = get_weaponinfo(j);
1866                                         if(wi.weapon)
1867                                                 if (!(wi.spawnflags & WEP_FLAG_MUTATORBLOCKED))
1868                                                         got += GiveWeapon(e, j, op, val);
1869                                 }
1870                         case "allammo":
1871                                 got += GiveValue(e, ammo_cells, op, val);
1872                                 got += GiveValue(e, ammo_plasma, op, val);
1873                                 got += GiveValue(e, ammo_shells, op, val);
1874                                 got += GiveValue(e, ammo_nails, op, val);
1875                                 got += GiveValue(e, ammo_rockets, op, val);
1876                                 got += GiveValue(e, ammo_fuel, op, val);
1877                                 break;
1878                         case "unlimited_ammo":
1879                                 got += GiveBit(e, items, IT_UNLIMITED_AMMO, op, val);
1880                                 break;
1881                         case "unlimited_weapon_ammo":
1882                                 got += GiveBit(e, items, IT_UNLIMITED_WEAPON_AMMO, op, val);
1883                                 break;
1884                         case "unlimited_superweapons":
1885                                 got += GiveBit(e, items, IT_UNLIMITED_SUPERWEAPONS, op, val);
1886                                 break;
1887                         case "jetpack":
1888                                 got += GiveBit(e, items, IT_JETPACK, op, val);
1889                                 break;
1890                         case "fuel_regen":
1891                                 got += GiveBit(e, items, IT_FUEL_REGEN, op, val);
1892                                 break;
1893                         case "strength":
1894                                 got += GiveValue(e, strength_finished, op, val);
1895                                 break;
1896                         case "invincible":
1897                                 got += GiveValue(e, invincible_finished, op, val);
1898                                 break;
1899                         case "superweapons":
1900                                 got += GiveValue(e, superweapons_finished, op, val);
1901                                 break;
1902                         case "cells":
1903                                 got += GiveValue(e, ammo_cells, op, val);
1904                                 break;
1905                         case "plasma":
1906                                 got += GiveValue(e, ammo_plasma, op, val);
1907                                 break;
1908                         case "shells":
1909                                 got += GiveValue(e, ammo_shells, op, val);
1910                                 break;
1911                         case "nails":
1912                         case "bullets":
1913                                 got += GiveValue(e, ammo_nails, op, val);
1914                                 break;
1915                         case "rockets":
1916                                 got += GiveValue(e, ammo_rockets, op, val);
1917                                 break;
1918                         case "health":
1919                                 got += GiveValue(e, health, op, val);
1920                                 break;
1921                         case "armor":
1922                                 got += GiveValue(e, armorvalue, op, val);
1923                                 break;
1924                         case "fuel":
1925                                 got += GiveValue(e, ammo_fuel, op, val);
1926                                 break;
1927                         default:
1928                                 for(j = WEP_FIRST; j <= WEP_LAST; ++j)
1929                                 {
1930                                         wi = get_weaponinfo(j);
1931                                         if(cmd == wi.netname)
1932                                         {
1933                                                 got += GiveWeapon(e, j, op, val);
1934                                                 break;
1935                                         }
1936                                 }
1937                                 if(j > WEP_LAST)
1938                                         print("give: invalid item ", cmd, "\n");
1939                                 break;
1940                 }
1941                 val = 999;
1942                 op = OP_SET;
1943         }
1944
1945         POSTGIVE_BIT(e, items, IT_FUEL_REGEN, "misc/itempickup.wav", string_null);
1946         POSTGIVE_BIT(e, items, IT_UNLIMITED_SUPERWEAPONS, "misc/powerup.wav", "misc/poweroff.wav");
1947         POSTGIVE_BIT(e, items, IT_UNLIMITED_WEAPON_AMMO, "misc/powerup.wav", "misc/poweroff.wav");
1948         POSTGIVE_BIT(e, items, IT_JETPACK, "misc/itempickup.wav", string_null);
1949         for(j = WEP_FIRST; j <= WEP_LAST; ++j)
1950         {
1951                 wi = get_weaponinfo(j);
1952                 if(wi.weapon)
1953                 {
1954                         POSTGIVE_WEAPON(e, j, "weapons/weaponpickup.wav", string_null);
1955                         if (!(save_weapons & WepSet_FromWeapon(j)))
1956                                 if(e.weapons & WepSet_FromWeapon(j))
1957                                         WEP_ACTION(wi.weapon, WR_INIT);
1958                 }
1959         }
1960         POSTGIVE_VALUE(e, strength_finished, 1, "misc/powerup.wav", "misc/poweroff.wav");
1961         POSTGIVE_VALUE(e, invincible_finished, 1, "misc/powerup_shield.wav", "misc/poweroff.wav");
1962         POSTGIVE_VALUE(e, ammo_nails, 0, "misc/itempickup.wav", string_null);
1963         POSTGIVE_VALUE(e, ammo_cells, 0, "misc/itempickup.wav", string_null);
1964         POSTGIVE_VALUE(e, ammo_plasma, 0, "misc/itempickup.wav", string_null);
1965         POSTGIVE_VALUE(e, ammo_shells, 0, "misc/itempickup.wav", string_null);
1966         POSTGIVE_VALUE(e, ammo_rockets, 0, "misc/itempickup.wav", string_null);
1967         POSTGIVE_VALUE_ROT(e, ammo_fuel, 1, pauserotfuel_finished, autocvar_g_balance_pause_fuel_rot, pauseregen_finished, autocvar_g_balance_pause_fuel_regen, "misc/itempickup.wav", string_null);
1968         POSTGIVE_VALUE_ROT(e, armorvalue, 1, pauserotarmor_finished, autocvar_g_balance_pause_armor_rot, pauseregen_finished, autocvar_g_balance_pause_health_regen, "misc/armor25.wav", string_null);
1969         POSTGIVE_VALUE_ROT(e, health, 1, pauserothealth_finished, autocvar_g_balance_pause_health_rot, pauseregen_finished, autocvar_g_balance_pause_health_regen, "misc/megahealth.wav", string_null);
1970
1971         if(e.superweapons_finished <= 0)
1972                 if(self.weapons & WEPSET_SUPERWEAPONS)
1973                         e.superweapons_finished = autocvar_g_balance_superweapons_time;
1974
1975         if(e.strength_finished <= 0)
1976                 e.strength_finished = 0;
1977         else
1978                 e.strength_finished += time;
1979         if(e.invincible_finished <= 0)
1980                 e.invincible_finished = 0;
1981         else
1982                 e.invincible_finished += time;
1983         if(e.superweapons_finished <= 0)
1984                 e.superweapons_finished = 0;
1985         else
1986                 e.superweapons_finished += time;
1987
1988         if (!(e.weapons & WepSet_FromWeapon(e.switchweapon)))
1989                 _switchweapon = TRUE;
1990         if(_switchweapon)
1991                 W_SwitchWeapon_Force(e, w_getbestweapon(e));
1992
1993         return got;
1994 }
1995 #endif