]> icculus.org git repositories - divverent/nexuiz.git/blob - data/qcsrc/server/t_items.qc
revert prepration for target_give, as it breaks some maps
[divverent/nexuiz.git] / data / qcsrc / server / t_items.qc
1
2 .float max_armorvalue;
3
4 void Item_Respawn (void)
5 {
6         self.model = self.mdl;          // restore original model
7         self.solid = SOLID_TRIGGER;     // allow it to be touched again
8         sound (self, CHAN_VOICE, "misc/itemrespawn.wav", 1, ATTN_NORM); // play respawn sound
9         setorigin (self, self.origin);
10
11         //pointparticles(particleeffectnum("item_respawn"), self.origin + self.mins_z * '0 0 1' + '0 0 48', '0 0 0', 1);
12         pointparticles(particleeffectnum("item_respawn"), self.origin + 0.5 * (self.mins + self.maxs), '0 0 0', 1);
13 }
14
15 void Item_Touch (void)
16 {
17         local entity oldself;
18         local float _switchweapon;
19         local float pickedup;
20         local float it;
21
22         // remove the item if it's currnetly in a NODROP brush or hits a NOIMPACT surface (such as sky)
23         if (((trace_dpstartcontents | trace_dphitcontents) & DPCONTENTS_NODROP) || (trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT))
24         {
25                 remove(self);
26                 return;
27         }
28         if (other.classname != "player")
29                 return;
30         if (other.deadflag)
31                 return;
32         if (self.solid != SOLID_TRIGGER)
33                 return;
34         if (self.owner == other)
35                 return;
36
37         // if nothing happens to other, just return without taking the item
38         pickedup = FALSE;
39         _switchweapon = FALSE;
40
41         if (g_minstagib)
42         {
43                 _switchweapon = TRUE;
44                 if (self.ammo_cells)
45                 {
46                         pickedup = TRUE;
47                         // play some cool sounds ;)
48                         centerprint(other, "\n");
49                         if(other.health <= 5)
50                                 announce(other, "announcer/robotic/lastsecond.ogg");
51                         else if(other.health < 50)
52                                 announce(other, "announcer/robotic/narrowly.ogg");
53                         // sound not available
54                         // else if(self.items == IT_CELLS)
55                         //      play2(other, "announce/robotic/ammo.ogg");
56
57                         if (self.items & IT_NEX)
58                                 W_GiveWeapon (other, IT_NEX, "Nex");
59                         if (self.ammo_cells)
60                                 other.ammo_cells = min (other.ammo_cells + cvar("g_minstagib_ammo_drop"), 999);
61                         other.health = 100;
62                 }
63
64                 // extralife powerup
65                 if (self.max_health)
66                 {
67                         pickedup = TRUE;
68                         // sound not available
69                         // play2(other, "announce/robotic/extra.ogg\nplay2 announce/robotic/_lives.ogg");
70                         other.armorvalue = other.armorvalue + cvar("g_minstagib_extralives");
71                         sprint(other, "^3You picked up some extra lives\n");
72                 }
73
74                 // invis powerup
75                 if (self.strength_finished)
76                 {
77                         pickedup = TRUE;
78                         // sound not available
79                         // play2(other, "announce/robotic/invisible.ogg");
80                         other.strength_finished = max(other.strength_finished, time) + cvar("g_balance_powerup_strength_time");
81                 }
82
83                 // speed powerup
84                 if (self.invincible_finished)
85                 {
86                         pickedup = TRUE;
87                         // sound not available
88                         // play2(other, "announce/robotic/speed.ogg");
89                         other.invincible_finished = max(other.invincible_finished, time) + cvar("g_balance_powerup_strength_time");
90                 }
91         }
92         else
93         {
94                 if (cvar("deathmatch") == 2 || cvar("g_weapon_stay"))
95                 {
96                         if (self.flags & FL_WEAPON && other.items & self.items && self.classname != "droppedweapon")
97                                 return;
98                         if (other.items & self.items && self.flags & FL_TOSSED) // don't let players stack ammo by tossing weapons
99                                 return;
100                 }
101
102                 // in case the player has autoswitch enabled do the following:
103                 // if the player is using their best weapon before items are given, they
104                 // probably want to switch to an even better weapon after items are given
105                 if (other.autoswitch)
106                 if (other.switchweapon == w_getbestweapon(other))
107                         _switchweapon = TRUE;
108
109                 if (self.ammo_shells)
110                 if (other.ammo_shells < g_pickup_shells_max)
111                 {
112                         pickedup = TRUE;
113                         other.ammo_shells = min (other.ammo_shells + self.ammo_shells, g_pickup_shells_max);
114                 }
115                 if (self.ammo_nails)
116                 if (other.ammo_nails < g_pickup_nails_max)
117                 {
118                         pickedup = TRUE;
119                         other.ammo_nails = min (other.ammo_nails + self.ammo_nails, g_pickup_nails_max);
120                 }
121                 if (self.ammo_rockets)
122                 if (other.ammo_rockets < g_pickup_rockets_max)
123                 {
124                         pickedup = TRUE;
125                         other.ammo_rockets = min (other.ammo_rockets + self.ammo_rockets, g_pickup_rockets_max);
126                 }
127                 if (self.ammo_cells)
128                 if (other.ammo_cells < g_pickup_cells_max)
129                 {
130                         pickedup = TRUE;
131                         other.ammo_cells = min (other.ammo_cells + self.ammo_cells, g_pickup_cells_max);
132                 }
133
134                 if (self.flags & FL_WEAPON)
135                 if ((it = self.items - (self.items & other.items)))
136                 {
137                         pickedup = TRUE;
138                         if (it & IT_UZI)                W_GiveWeapon (other, IT_UZI, self.netname);
139                         if (it & IT_SHOTGUN)            W_GiveWeapon (other, IT_SHOTGUN, self.netname);
140                         if (it & IT_GRENADE_LAUNCHER)   W_GiveWeapon (other, IT_GRENADE_LAUNCHER, self.netname);
141                         if (it & IT_ELECTRO)            W_GiveWeapon (other, IT_ELECTRO, self.netname);
142                         if (it & IT_NEX)                W_GiveWeapon (other, IT_NEX, self.netname);
143                         if (it & IT_HAGAR)              W_GiveWeapon (other, IT_HAGAR, self.netname);
144                         if (it & IT_ROCKET_LAUNCHER)    W_GiveWeapon (other, IT_ROCKET_LAUNCHER, self.netname);
145                         if (it & IT_CRYLINK)            W_GiveWeapon (other, IT_CRYLINK, self.netname);
146                 }
147
148                 if (self.strength_finished)
149                 {
150                         pickedup = TRUE;
151                         other.strength_finished = max(other.strength_finished, time) + cvar("g_balance_powerup_strength_time");
152                 }
153                 if (self.invincible_finished)
154                 {
155                         pickedup = TRUE;
156                         other.invincible_finished = max(other.invincible_finished, time) + cvar("g_balance_powerup_invincible_time");
157                 }
158                 //if (self.speed_finished)
159                 //{
160                 //      pickedup = TRUE;
161                 //      other.speed_finished = max(other.speed_finished, time) + cvar("g_balance_powerup_speed_time");
162                 //}
163                 //if (self.slowmo_finished)
164                 //{
165                 //      pickedup = TRUE;
166                 //      other.slowmo_finished = max(other.slowmo_finished, time) + (cvar("g_balance_powerup_slowmo_time") * cvar("g_balance_powerup_slowmo_speed"));
167                 //}
168
169                 if (self.health)
170                 if (other.health < self.max_health)
171                 {
172                         pickedup = TRUE;
173                         other.health = min(other.health + self.health, self.max_health);
174                         other.pauserothealth_finished = max(other.pauserothealth_finished, time + cvar("g_balance_pause_health_rot"));
175                 }
176                 if (self.armorvalue)
177                 if (other.armorvalue < self.max_armorvalue)
178                 {
179                         pickedup = TRUE;
180                         other.armorvalue = min(other.armorvalue + self.armorvalue, self.max_armorvalue);
181                         other.pauserotarmor_finished = max(other.pauserotarmor_finished, time + cvar("g_balance_pause_armor_rot"));
182                 }
183         }
184
185         if (!pickedup)
186                 return;
187
188         sound (self, CHAN_BODY, self.noise, 1, ATTN_NORM);
189         sound (other, CHAN_AUTO, self.item_pickupsound, 1, ATTN_NORM);
190
191         oldself = self;
192         self = other;
193
194         if (_switchweapon)
195                 self.switchweapon = w_getbestweapon(self);
196         if (self.switchweapon != self.weapon)
197                 self.cnt = self.weapon;
198
199         self = oldself;
200
201         if (self.classname == "droppedweapon")
202                 remove (self);
203         else if(self.flags & FL_WEAPON && (cvar("deathmatch") == 2 || cvar("g_weapon_stay")))
204                 return;
205         else
206         {
207                 self.solid = SOLID_NOT;
208                 self.model = string_null;
209                 self.nextthink = time + self.respawntime;
210                 self.think = Item_Respawn;
211                 setorigin (self, self.origin);
212         }
213 }
214
215 // Savage: used for item garbage-collection
216 // TODO: perhaps nice special effect?
217 void RemoveItem(void) = {
218         remove(self);
219 }
220
221 // pickup evaluation functions
222 // these functions decide how desirable an item is to the bots
223
224 float(entity player, entity item) generic_pickupevalfunc = {return item.bot_pickupbasevalue;};
225
226 float(entity player, entity item) weapon_pickupevalfunc =
227 {
228         // if we already have the weapon, rate it 1/5th normal value
229         if ((player.items & item.items) == item.items)
230                 return item.bot_pickupbasevalue * 0.2;
231         return item.bot_pickupbasevalue;
232 };
233
234 float(entity player, entity item) commodity_pickupevalfunc =
235 {
236         float c;
237         c = 0;
238         // TODO: figure out if the player even has the weapon this ammo is for?
239         // may not affect strategy much though...
240         // find out how much more ammo/armor/health the player can hold
241         if (item.ammo_shells)
242         if (player.ammo_shells < g_pickup_shells_max)
243                 c = c + max(0, 1 - player.ammo_shells / g_pickup_shells_max);
244         if (item.ammo_nails)
245         if (player.ammo_nails < g_pickup_nails_max)
246                 c = c + max(0, 1 - player.ammo_nails / g_pickup_nails_max);
247         if (item.ammo_rockets)
248         if (player.ammo_rockets < g_pickup_rockets_max)
249                 c = c + max(0, 1 - player.ammo_rockets / g_pickup_rockets_max);
250         if (item.ammo_cells)
251         if (player.ammo_cells < g_pickup_cells_max)
252                 c = c + max(0, 1 - player.ammo_cells / g_pickup_cells_max);
253         if (item.armorvalue)
254         if (player.armorvalue < item.max_armorvalue)
255                 c = c + max(0, 1 - player.armorvalue / item.max_armorvalue);
256         if (item.health)
257         if (player.health < item.max_health)
258                 c = c + max(0, 1 - player.health / item.max_health);
259
260         if (cvar("deathmatch") == 2) // weapon stay is on, so weapons the player already has are of no interest
261         if (item.flags & FL_WEAPON)
262         if (self.items & item.items)
263         if (item.classname != "droppedweapon")
264                 c = 0;
265
266         return item.bot_pickupbasevalue * c;
267 };
268
269
270 .float is_item;
271 void StartItem (string itemmodel, string pickupsound, float defaultrespawntime, string itemname, float itemid, float itemflags, float(entity player, entity item) pickupevalfunc, float pickupbasevalue)
272 {
273         startitem_failed = FALSE;
274
275         if (self.classname != "droppedweapon")
276         {
277                 if(teams_matter)
278                 {
279                         if(self.notteam)
280                         {
281                                 print("removed non-teamplay ", self.classname, "\n");
282                                 startitem_failed = TRUE;
283                                 remove (self);
284                                 return;
285                         }
286                 }
287                 else
288                 {
289                         if(self.notfree)
290                         {
291                                 print("removed non-FFA ", self.classname, "\n");
292                                 startitem_failed = TRUE;
293                                 remove (self);
294                                 return;
295                         }
296                 }
297
298                 if(self.notq3a)
299                 {
300                         // We aren't TA or something like that, so we keep the Q3A entities
301                         print("removed non-Q3A ", self.classname, "\n");
302                         startitem_failed = TRUE;
303                         remove (self);
304                         return;
305                 }
306                 
307                 /*
308                  * can't do it that way, as it would break maps
309                  * TODO make a target_give like entity another way, that perhaps has
310                  * the weapon name in a key
311                 if(self.targetname)
312                 {
313                         // target_give not yet supported; maybe later
314                         print("removed targeted ", self.classname, "\n");
315                         startitem_failed = TRUE;
316                         remove (self);
317                         return;
318                 }
319                 */
320                 
321                 if(cvar("spawn_debug") >= 2)
322                 {
323                         entity otheritem;
324                         for(otheritem = findradius(self.origin, 3); otheritem; otheritem = otheritem.chain)
325                         {
326                                 if(otheritem.is_item)
327                                 {
328                                         dprint("XXX Found duplicated item: ", itemname, vtos(self.origin));
329                                         dprint(" vs ", otheritem.netname, vtos(otheritem.origin), "\n");
330                                         error("Mapper sucks.");
331                                 }
332                         }
333                         self.is_item = TRUE;
334                 }
335
336                 waypoint_spawnforitem(self);
337
338                 itemsInMap |= itemid;
339         }
340
341         if (!(cvar("g_pickup_items") && !g_nixnex) && !g_minstagib &&
342                         itemid != IT_STRENGTH && itemid != IT_INVINCIBLE && itemid != IT_HEALTH)
343         {
344                 startitem_failed = TRUE;
345                 remove (self);
346                 return;
347         }
348
349         if (g_minstagib)
350         {
351                 // don't remove dropped items and powerups
352                 if (self.classname != "droppedweapon" &&
353                     self.classname != "minstagib")
354                 {
355                         startitem_failed = TRUE;
356                         remove (self);
357                         return;
358                 }
359         }
360
361         if(g_lms && (self.classname != "droppedweapon"))
362         {
363                 startitem_failed = TRUE;
364                 remove(self);
365                 return;
366         }
367
368         if(g_instagib || g_rocketarena)
369         {
370                 startitem_failed = TRUE;
371                 remove(self);
372                 return;
373         }
374
375         if (self.classname == "droppedweapon")
376         {
377                 // don't drop if in a NODROP zone (such as lava)
378                 traceline(self.origin, self.origin, MOVE_NORMAL, self);
379                 if (trace_dpstartcontents & DPCONTENTS_NODROP)
380                 {
381                         startitem_failed = TRUE;
382                         remove(self);
383                         return;
384                 }
385         }
386
387         if (self.classname != "droppedweapon")
388         {
389                 precache_model (itemmodel);
390                 precache_sound (pickupsound);
391                 precache_sound ("misc/itemrespawn.wav");
392         }
393
394         if(itemid & (IT_STRENGTH | IT_INVINCIBLE | IT_HEALTH | IT_ARMOR | IT_KEY1 | IT_KEY2 |
395                                 IT_ROCKET_LAUNCHER | IT_HAGAR | IT_NEX | IT_CRYLINK | IT_ELECTRO |
396                                 IT_GRENADE_LAUNCHER | IT_UZI | IT_SHOTGUN | IT_LASER) && self.classname != "droppedweapon")
397         {
398                 self.target = "###item###"; // for finding the nearest item using find()
399         }
400         self.bot_pickup = TRUE;
401         self.bot_pickupevalfunc = pickupevalfunc;
402         self.bot_pickupbasevalue = pickupbasevalue;
403         self.mdl = itemmodel;
404         //self.noise = pickupsound;
405         self.item_pickupsound = pickupsound;
406         // let mappers override respawntime
407         if (!self.respawntime)
408                 self.respawntime = defaultrespawntime;
409         self.netname = itemname;
410         self.items = itemid;
411         self.flags = FL_ITEM | itemflags;
412         if(self.spawnflags & 1)
413                 self.noalign = 1;
414         if (self.noalign)
415                 self.movetype = MOVETYPE_NONE;
416         else
417                 self.movetype = MOVETYPE_TOSS;
418         self.solid = SOLID_TRIGGER;
419         self.touch = Item_Touch;
420         setmodel (self, self.mdl); // precision set below
421         self.effects |= EF_LOWPRECISION;
422         if((itemflags & FL_POWERUP) || self.health || self.armorvalue)
423                 setsize (self, '-16 -16 0', '16 16 48');
424         else
425                 setsize (self, '-16 -16 0', '16 16 32');
426         if (itemflags & FL_WEAPON)
427         {
428                 // neutral team color for pickup weapons
429                 self.colormap = 160 * 1024 + 160;
430         }
431
432         // Savage: remove thrown items after a certain period of time ("garbage collection")
433         if (self.classname == "droppedweapon")
434         {
435                 self.think = RemoveItem;
436                 self.nextthink = time + 60;
437         }
438         else if (!self.noalign)
439         {
440                 // first nudge it off the floor a little bit to avoid math errors
441                 setorigin(self, self.origin + '0 0 1');
442                 // note droptofloor returns FALSE if stuck/or would fall too far
443                 droptofloor();
444         }
445
446         if (cvar("g_fullbrightitems"))
447                 self.effects = self.effects | EF_FULLBRIGHT;
448 }
449
450 /* replace items in minstagib
451  * IT_STRENGTH   = invisibility
452  * IT_NAILS      = extra lives
453  * IT_INVINCIBLE = speed
454  */
455 void minstagib_items (float itemid)
456 {
457         // we don't want to replace dropped weapons ;)
458         if (self.classname == "droppedweapon")
459         {
460                 self.ammo_cells = 25;
461                 StartItem ("models/weapons/g_nex.md3",
462                         "weapons/weaponpickup.wav", 15,
463                         "Nex Gun", IT_NEX, FL_WEAPON, generic_pickupevalfunc, 1000);
464                 return;
465         }
466
467         local float rnd;
468         self.classname = "minstagib";
469
470         // replace rocket launchers and nex guns with ammo cells
471         if (itemid == IT_CELLS)
472         {
473                 self.ammo_cells = 1;
474                 StartItem ("models/items/a_cells.md3",
475                         "misc/itempickup.wav", 45,
476                         "Nex Ammo", IT_CELLS, 0, generic_pickupevalfunc, 100);
477                 return;
478         }
479
480         // randomize
481         rnd = random() * 3;
482         if (rnd <= 1)
483                 itemid = IT_STRENGTH;
484         else if (rnd <= 2)
485                 itemid = IT_NAILS;
486         else
487                 itemid = IT_INVINCIBLE;
488
489         // replace with invis
490         if (itemid == IT_STRENGTH)
491         {
492                 self.effects = EF_ADDITIVE;
493                 self.strength_finished = 30;
494                 StartItem ("models/items/g_strength.md3",
495                         "misc/powerup.wav", 120,
496                         "Invisibility", IT_STRENGTH, FL_POWERUP, generic_pickupevalfunc, 1000);
497         }
498         // replace with extra lives
499         if (itemid == IT_NAILS)
500         {
501                 self.max_health = 1;
502                 StartItem ("models/items/g_h100.md3",
503                         "misc/megahealth.wav", 120,
504                         "Extralife", IT_NAILS, FL_POWERUP, generic_pickupevalfunc, 1000);
505
506         }
507         // replace with speed
508         if (itemid == IT_INVINCIBLE)
509         {
510                 self.effects = EF_ADDITIVE;
511                 self.invincible_finished = 30;
512                 StartItem ("models/items/g_invincible.md3",
513                         "misc/powerup_shield.wav", 120,
514                         "Speed", IT_INVINCIBLE, FL_POWERUP, generic_pickupevalfunc, 1000);
515         }
516
517 }
518
519 float minst_no_auto_cells;
520 void minst_remove_item (void) {
521         if(minst_no_auto_cells)
522                 remove(self);
523 }
524
525 float weaponswapping;
526
527 void weapon_shotgun (void);
528 void weapon_uzi (void) {
529         if(!weaponswapping)
530         if(q3acompat_machineshotgunswap)
531         if(self.classname != "droppedweapon")
532         {
533                 weaponswapping = TRUE;
534                 weapon_shotgun();
535                 weaponswapping = FALSE;
536                 return;
537         }
538
539         if(!self.ammo_nails)
540                 self.ammo_nails = cvar("g_pickup_nails");
541         StartItem ("models/weapons/g_uzi.md3", "weapons/weaponpickup.wav", 15, W_Name(WEP_UZI), IT_UZI, FL_WEAPON, weapon_pickupevalfunc, 20000);
542         if (self.modelindex) // don't precache if self was removed
543                 weapon_action(WEP_UZI, WR_PRECACHE);
544 }
545
546 void weapon_shotgun (void) {
547         if(!weaponswapping)
548         if(q3acompat_machineshotgunswap)
549         if(self.classname != "droppedweapon")
550         {
551                 weaponswapping = TRUE;
552                 weapon_uzi();
553                 weaponswapping = FALSE;
554                 return;
555         }
556
557         if(!self.ammo_shells)
558                 self.ammo_shells = cvar("g_pickup_shells");
559         StartItem ("models/weapons/g_shotgun.md3", "weapons/weaponpickup.wav", 15, W_Name(WEP_SHOTGUN), IT_SHOTGUN, FL_WEAPON, weapon_pickupevalfunc, 10000);
560         if (self.modelindex) // don't precache if self was removed
561                 weapon_action(WEP_SHOTGUN, WR_PRECACHE);
562 }
563
564 void weapon_grenadelauncher (void)
565 {
566         if(!self.ammo_rockets)
567                 self.ammo_rockets = cvar("g_pickup_rockets");
568         StartItem ("models/weapons/g_gl.md3", "weapons/weaponpickup.wav", 15, W_Name(WEP_GRENADE_LAUNCHER), IT_GRENADE_LAUNCHER, FL_WEAPON, weapon_pickupevalfunc, 20000);
569         if (self.modelindex) // don't precache if self was removed
570                 weapon_action(WEP_GRENADE_LAUNCHER, WR_PRECACHE);
571 }
572
573 void weapon_electro (void)
574 {
575         if(!self.ammo_cells)
576                 self.ammo_cells = cvar("g_pickup_cells");
577         StartItem ("models/weapons/g_electro.md3", "weapons/weaponpickup.wav", 15, W_Name(WEP_ELECTRO), IT_ELECTRO, FL_WEAPON, weapon_pickupevalfunc, 15000);
578         if (self.modelindex) // don't precache if self was removed
579                 weapon_action(WEP_ELECTRO, WR_PRECACHE);
580 }
581
582 void weapon_crylink (void)
583 {
584         if(!self.ammo_cells)
585                 self.ammo_cells = cvar("g_pickup_cells");
586         StartItem ("models/weapons/g_crylink.md3", "weapons/weaponpickup.wav", 15, W_Name(WEP_CRYLINK), IT_CRYLINK, FL_WEAPON, weapon_pickupevalfunc, 10000);
587         if (self.modelindex) // don't precache if self was removed
588                 weapon_action(WEP_CRYLINK, WR_PRECACHE);
589 }
590
591 void weapon_nex (void)
592 {
593         float nextime;
594         if (g_minstagib)
595         {
596                 minstagib_items(IT_CELLS);
597                 self.think = minst_remove_item;
598                 self.nextthink = time + cvar("sys_ticrate");
599                 return;
600         }
601         if(!self.ammo_cells)
602                 self.ammo_cells = cvar("g_pickup_cells");
603         nextime = cvar("g_balance_nex_respawntime_modifier");
604         if(nextime)
605                 nextime = 15 * nextime;
606         else
607                 nextime = 15;
608         StartItem ("models/weapons/g_nex.md3", "weapons/weaponpickup.wav", nextime, W_Name(WEP_NEX), IT_NEX, FL_WEAPON, weapon_pickupevalfunc, 30000);
609         if (self.modelindex) // don't precache if self was removed
610                 weapon_action(WEP_NEX, WR_PRECACHE);
611 }
612
613 void weapon_hagar (void)
614 {
615         if(!self.ammo_rockets)
616                 self.ammo_rockets = cvar("g_pickup_rockets");
617         StartItem ("models/weapons/g_hagar.md3", "weapons/weaponpickup.wav", 15, W_Name(WEP_HAGAR), IT_HAGAR, FL_WEAPON, weapon_pickupevalfunc, 10000);
618         if (self.modelindex) // don't precache if self was removed
619                 weapon_action(WEP_HAGAR, WR_PRECACHE);
620 }
621
622 void weapon_rocketlauncher (void)
623 {
624         if (g_minstagib)
625         {
626                 minstagib_items(IT_CELLS);
627                 self.think = minst_remove_item;
628                 self.nextthink = time + cvar("sys_ticrate");
629                 return;
630         }
631         if(!self.ammo_rockets)
632                 self.ammo_rockets = g_pickup_rockets;
633         StartItem ("models/weapons/g_rl.md3", "weapons/weaponpickup.wav", 15, W_Name(WEP_ROCKET_LAUNCHER), IT_ROCKET_LAUNCHER, FL_WEAPON, weapon_pickupevalfunc, 30000);
634         if (self.modelindex) // don't precache if self was removed
635                 weapon_action(WEP_ROCKET_LAUNCHER, WR_PRECACHE);
636 }
637
638 void item_rockets (void) {
639         if(!self.ammo_rockets)
640                 self.ammo_rockets = g_pickup_rockets;
641         StartItem ("models/items/a_rockets.md3", "misc/itempickup.wav", 15, "rockets", IT_ROCKETS, 0, commodity_pickupevalfunc, 3000);
642 }
643
644 void item_shells (void);
645 void item_bullets (void) {
646         if(!weaponswapping)
647         if(q3acompat_machineshotgunswap)
648         if(self.classname != "droppedweapon")
649         {
650                 weaponswapping = TRUE;
651                 item_shells();
652                 weaponswapping = FALSE;
653                 return;
654         }
655
656         if(!self.ammo_nails)
657                 self.ammo_nails = g_pickup_nails;
658         StartItem ("models/items/a_bullets.mdl", "misc/itempickup.wav", 15, "bullets", IT_NAILS, 0, commodity_pickupevalfunc, 2000);
659 }
660
661 void item_cells (void) {
662         if(!self.ammo_cells)
663                 self.ammo_cells = g_pickup_cells;
664         StartItem ("models/items/a_cells.md3", "misc/itempickup.wav", 15, "cells", IT_CELLS, 0, commodity_pickupevalfunc, 2000);
665 }
666
667 void item_shells (void) {
668         if(!weaponswapping)
669         if(q3acompat_machineshotgunswap)
670         if(self.classname != "droppedweapon")
671         {
672                 weaponswapping = TRUE;
673                 item_bullets();
674                 weaponswapping = FALSE;
675                 return;
676         }
677
678         if(!self.ammo_shells)
679                 self.ammo_shells = g_pickup_shells;
680         StartItem ("models/items/a_shells.md3", "misc/itempickup.wav", 15, "shells", IT_SHELLS, 0, commodity_pickupevalfunc, 500);
681 }
682
683 void item_armor_small (void) {
684         if(!self.armorvalue)
685                 self.armorvalue = g_pickup_armorsmall;
686         if(!self.max_armorvalue)
687                 self.max_armorvalue = g_pickup_armorsmall_max;
688         StartItem ("models/items/g_a1.md3", "misc/armor1.wav", 15, "5 Armor", IT_ARMOR_SHARD, 0, commodity_pickupevalfunc, 1000);
689 }
690
691 void item_armor_medium (void) {
692         if(!self.armorvalue)
693                 self.armorvalue = g_pickup_armormedium;
694         if(!self.max_armorvalue)
695                 self.max_armorvalue = g_pickup_armormedium_max;
696         StartItem ("models/items/g_armormedium.md3", "misc/armor1.wav", 30, "25 Armor", IT_ARMOR, 0, commodity_pickupevalfunc, 20000);
697 }
698
699 void item_armor_large (void) {
700         if(!self.armorvalue)
701                 self.armorvalue = g_pickup_armorlarge;
702         if(!self.max_armorvalue)
703                 self.max_armorvalue = g_pickup_armorlarge_max;
704         StartItem ("models/items/g_a25.md3", "misc/armor25.wav", 30, "100 Armor", IT_ARMOR, 0, commodity_pickupevalfunc, 20000);
705 }
706
707 void item_health_small (void) {
708         if(!self.max_health)
709                 self.max_health = g_pickup_healthsmall_max;
710         if(!self.health)
711                 self.health = g_pickup_healthsmall;
712         StartItem ("models/items/g_h1.md3", "misc/minihealth.wav", 15, "5 Health", IT_5HP, 0, commodity_pickupevalfunc, 1000);
713 }
714
715 void item_health_medium (void) {
716         if(!self.max_health)
717                 self.max_health = g_pickup_healthmedium_max;
718         if(!self.health)
719                 self.health = g_pickup_healthmedium;
720         StartItem ("models/items/g_h25.md3", "misc/mediumhealth.wav", 15, "25 Health", IT_25HP, 0, commodity_pickupevalfunc, 5000);
721 }
722
723 void item_health_large (void) {
724         if(!self.max_health)
725                 self.max_health = g_pickup_healthlarge_max;
726         if(!self.health)
727                 self.health = g_pickup_healthlarge;
728         StartItem ("models/items/g_h50.md3", "misc/mediumhealth.wav", 15, "50 Health", IT_25HP, 0, commodity_pickupevalfunc, 5000);
729 }
730
731 void item_health_mega (void) {
732         if(!cvar("g_powerup_superhealth"))
733                 return;
734
735         if(g_arena && !cvar("g_arena_powerups"))
736                 return;
737
738         if(g_minstagib) {
739                 minstagib_items(IT_NAILS);
740         } else {
741                 if(!self.max_health)
742                         self.max_health = g_pickup_healthmega_max;
743                 if(!self.health)
744                         self.health = g_pickup_healthmega;
745                 StartItem ("models/items/g_h100.md3", "misc/megahealth.wav", 30, "100 Health", IT_HEALTH, 0, commodity_pickupevalfunc, 20000);
746         }
747 }
748
749 // support old misnamed entities
750 void item_armor1() { item_armor_small(); }
751 void item_armor25() { item_armor_large(); }
752 void item_health1() { item_health_small(); }
753 void item_health25() { item_health_medium(); }
754 void item_health100() { item_health_mega(); }
755
756 void item_strength (void) {
757         if(!cvar("g_powerup_strength"))
758                 return;
759
760         if(g_arena && !cvar("g_arena_powerups"))
761                 return;
762
763         if(g_minstagib) {
764                 minstagib_items(IT_STRENGTH);
765         } else {
766                 precache_sound("weapons/strength_fire.wav");
767                 self.strength_finished = 30;
768                 self.effects = EF_ADDITIVE;StartItem ("models/items/g_strength.md3", "misc/powerup.wav", 120, "Strength Powerup", IT_STRENGTH, FL_POWERUP, generic_pickupevalfunc, 100000);
769         }
770 }
771
772 void item_invincible (void) {
773         if(!cvar("g_powerup_shield"))
774                 return;
775
776         if(g_arena && !cvar("g_arena_powerups"))
777                 return;
778
779         if(g_minstagib) {
780                 minstagib_items(IT_INVINCIBLE);
781         } else {
782                 self.invincible_finished = 30;
783                 self.effects = EF_ADDITIVE;
784                 StartItem ("models/items/g_invincible.md3", "misc/powerup_shield.wav", 120, "Invulnerability", IT_INVINCIBLE, FL_POWERUP, generic_pickupevalfunc, 100000);
785         }
786 }
787 //void item_speed (void) {self.speed_finished = 30;StartItem ("models/items/g_speed.md3", "misc/powerup.wav", 120, "Speed Powerup", IT_SPEED, FL_POWERUP, generic_pickupevalfunc, 10000);}
788 //void item_slowmo (void) {self.slowmo_finished = 30;StartItem ("models/items/g_slowmo.md3", "misc/powerup.wav", 120, "Slow Motion", IT_SLOWMO, FL_POWERUP, generic_pickupevalfunc, 10000);}
789
790 void item_minst_cells (void) {
791         if (g_minstagib)
792         {
793                 minst_no_auto_cells = 1;
794                 minstagib_items(IT_CELLS);
795         }
796         else
797                 remove(self);
798 }
799
800 // compatibility:
801 void item_quad (void) {self.classname = "item_strength";item_strength();}
802
803 void misc_models (void)
804 {
805         precache_model (self.model);
806         setmodel (self, self.model); // precision set by mapper
807         setsize (self, self.mins, self.maxs);
808 }
809
810 void func_wall_use (void)
811 {
812         if(teams_matter)
813         {
814                 if(activator.team)
815                         self.colormap = (activator.team - 1) * 0x11;
816                 else
817                         self.colormap = 0x00;
818         }
819         else
820                 self.colormap = ceil(random() * 256) - 1;
821         self.colormap |= 1024; // RENDER_COLORMAPPED
822 }
823
824 void func_wall (void)
825 {
826         precache_model (self.model);
827         setmodel (self, self.model); // precision set by mapper
828         setsize (self, self.mins, self.maxs);
829         self.solid = SOLID_BSP;
830         self.use = func_wall_use;
831 }
832
833 floatfield Item_CounterField(float it)
834 {
835         switch(it)
836         {
837                 case IT_SHELLS:      return ammo_shells;
838                 case IT_NAILS:       return ammo_nails;
839                 case IT_ROCKETS:     return ammo_rockets;
840                 case IT_CELLS:       return ammo_cells;
841                 case IT_5HP:         return health;
842                 case IT_25HP:        return health;
843                 case IT_HEALTH:      return health;
844                 case IT_ARMOR_SHARD: return armorvalue;
845                 case IT_ARMOR:       return armorvalue;
846                 // add more things here (health, armor)
847                 default:             error("requested item has no counter field");
848         }
849 }
850
851 float Item_WeaponCode(float it)
852 {
853         switch(it)
854         {
855                 case IT_LASER:            return WEP_LASER;
856                 case IT_SHOTGUN:          return WEP_SHOTGUN;
857                 case IT_UZI:              return WEP_UZI;
858                 case IT_GRENADE_LAUNCHER: return WEP_GRENADE_LAUNCHER;
859                 case IT_ELECTRO:          return WEP_ELECTRO;
860                 case IT_CRYLINK:          return WEP_CRYLINK;
861                 case IT_NEX:              return WEP_NEX;
862                 case IT_HAGAR:            return WEP_HAGAR;
863                 case IT_ROCKET_LAUNCHER:  return WEP_ROCKET_LAUNCHER;
864                 default:                  return 0;
865         }
866 }
867
868 void Item_SpawnByItemCode(float it)
869 {
870         switch(it)
871         {
872                 case IT_SHOTGUN:          weapon_shotgun(); break;
873                 case IT_UZI:              weapon_uzi(); break;
874                 case IT_GRENADE_LAUNCHER: weapon_grenadelauncher(); break;
875                 case IT_ELECTRO:          weapon_electro(); break;
876                 case IT_CRYLINK:          weapon_crylink(); break;
877                 case IT_NEX:              weapon_nex(); break;
878                 case IT_HAGAR:            weapon_hagar(); break;
879                 case IT_ROCKET_LAUNCHER:  weapon_rocketlauncher(); break;
880                 // add all other item spawn functions here
881                 default:
882                         error("requested item can't be spawned");
883         }
884 }