]> icculus.org git repositories - divverent/nexuiz.git/blob - data/qcsrc/server/t_items.qc
no-operation change to pave the way for fuel and jetpack pickups
[divverent/nexuiz.git] / data / qcsrc / server / t_items.qc
1 floatfield Item_CounterField(float it)
2 {
3         switch(it)
4         {
5                 case IT_SHELLS:      return ammo_shells;
6                 case IT_NAILS:       return ammo_nails;
7                 case IT_ROCKETS:     return ammo_rockets;
8                 case IT_CELLS:       return ammo_cells;
9                 case IT_FUEL:        return ammo_fuel;
10                 case IT_5HP:         return health;
11                 case IT_25HP:        return health;
12                 case IT_HEALTH:      return health;
13                 case IT_ARMOR_SHARD: return armorvalue;
14                 case IT_ARMOR:       return armorvalue;
15                 // add more things here (health, armor)
16                 default:             error("requested item has no counter field");
17         }
18 }
19
20 string Item_CounterFieldName(float it)
21 {
22         switch(it)
23         {
24                 case IT_SHELLS:      return "shells";
25                 case IT_NAILS:       return "nails";
26                 case IT_ROCKETS:     return "rockets";
27                 case IT_CELLS:       return "cells";
28                 case IT_FUEL:        return "fuel";
29
30                 // add more things here (health, armor)
31                 default:             error("requested item has no counter field name");
32         }
33 }
34
35 .float max_armorvalue;
36
37 void Item_Respawn (void)
38 {
39         self.model = self.mdl;          // restore original model
40         self.solid = SOLID_TRIGGER;     // allow it to be touched again
41         sound (self, CHAN_TRIGGER, "misc/itemrespawn.wav", VOL_BASE, ATTN_NORM);        // play respawn sound
42         setorigin (self, self.origin);
43
44         //pointparticles(particleeffectnum("item_respawn"), self.origin + self.mins_z * '0 0 1' + '0 0 48', '0 0 0', 1);
45         pointparticles(particleeffectnum("item_respawn"), self.origin + 0.5 * (self.mins + self.maxs), '0 0 0', 1);
46 }
47
48 float Item_GiveTo(entity item, entity player)
49 {
50         float _switchweapon;
51         float pickedup;
52         float it;
53         float i;
54         entity e;
55
56         // if nothing happens to player, just return without taking the item
57         pickedup = FALSE;
58         _switchweapon = FALSE;
59
60         if (g_minstagib)
61         {
62                 _switchweapon = TRUE;
63                 if (item.ammo_cells)
64                 {
65                         pickedup = TRUE;
66                         // play some cool sounds ;)
67                         centerprint(player, "\n");
68                         if(player.health <= 5)
69                                 announce(player, "announcer/robotic/lastsecond.wav");
70                         else if(player.health < 50)
71                                 announce(player, "announcer/robotic/narrowly.wav");
72                         // sound not available
73                         // else if(item.items == IT_CELLS)
74                         //      play2(player, "announce/robotic/ammo.wav");
75
76                         if (item.weapons & WEPBIT_MINSTANEX)
77                                 W_GiveWeapon (player, WEP_MINSTANEX, "Nex");
78                         if (item.ammo_cells)
79                                 player.ammo_cells = min (player.ammo_cells + cvar("g_minstagib_ammo_drop"), 999);
80                         player.health = 100;
81                 }
82
83                 // extralife powerup
84                 if (item.max_health)
85                 {
86                         pickedup = TRUE;
87                         // sound not available
88                         // play2(player, "announce/robotic/extra.ogg\nplay2 announce/robotic/_lives.wav");
89                         player.armorvalue = player.armorvalue + cvar("g_minstagib_extralives");
90                         sprint(player, "^3You picked up some extra lives\n");
91                 }
92
93                 // invis powerup
94                 if (item.strength_finished)
95                 {
96                         pickedup = TRUE;
97                         // sound not available
98                         // play2(player, "announce/robotic/invisible.wav");
99                         player.strength_finished = max(player.strength_finished, time) + cvar("g_balance_powerup_strength_time");
100                 }
101
102                 // speed powerup
103                 if (item.invincible_finished)
104                 {
105                         pickedup = TRUE;
106                         // sound not available
107                         // play2(player, "announce/robotic/speed.wav");
108                         player.invincible_finished = max(player.invincible_finished, time) + cvar("g_balance_powerup_strength_time");
109                 }
110         }
111         else
112         {
113                 if (g_weapon_stay == 1)
114                 if not(item.flags & FL_NO_WEAPON_STAY)
115                 if (item.flags & FL_WEAPON)
116                 {
117                         if(item.classname == "droppedweapon")
118                         {
119                                 if (player.weapons & item.weapons)      // don't let players stack ammo by tossing weapons
120                                         goto skip;
121                         }
122                         else
123                         {
124                                 if (player.weapons & item.weapons)
125                                         goto skip;
126                         }
127                 }
128
129                 // in case the player has autoswitch enabled do the following:
130                 // if the player is using their best weapon before items are given, they
131                 // probably want to switch to an even better weapon after items are given
132                 if (player.autoswitch)
133                 if (player.switchweapon == w_getbestweapon(player))
134                         _switchweapon = TRUE;
135
136                 if not(player.weapons & W_WeaponBit(player.switchweapon))
137                         _switchweapon = TRUE;
138
139                 if (item.ammo_shells)
140                 if (player.ammo_shells < g_pickup_shells_max)
141                 {
142                         pickedup = TRUE;
143                         player.ammo_shells = min (player.ammo_shells + item.ammo_shells, g_pickup_shells_max);
144                 }
145                 if (item.ammo_nails)
146                 if (player.ammo_nails < g_pickup_nails_max)
147                 {
148                         pickedup = TRUE;
149                         player.ammo_nails = min (player.ammo_nails + item.ammo_nails, g_pickup_nails_max);
150                 }
151                 if (item.ammo_rockets)
152                 if (player.ammo_rockets < g_pickup_rockets_max)
153                 {
154                         pickedup = TRUE;
155                         player.ammo_rockets = min (player.ammo_rockets + item.ammo_rockets, g_pickup_rockets_max);
156                 }
157                 if (item.ammo_cells)
158                 if (player.ammo_cells < g_pickup_cells_max)
159                 {
160                         pickedup = TRUE;
161                         player.ammo_cells = min (player.ammo_cells + item.ammo_cells, g_pickup_cells_max);
162                 }
163                 if (item.ammo_fuel)
164                 if (player.ammo_fuel < g_pickup_fuel_max)
165                 {
166                         pickedup = TRUE;
167                         player.ammo_fuel = min (player.ammo_fuel + item.ammo_fuel, g_pickup_fuel_max);
168                 }
169
170                 if (item.flags & FL_WEAPON)
171                 if ((it = item.weapons - (item.weapons & player.weapons)))
172                 {
173                         pickedup = TRUE;
174                         for(i = WEP_FIRST; i <= WEP_LAST; ++i)
175                         {
176                                 e = get_weaponinfo(i);
177                                 if(it & e.weapons)
178                                         W_GiveWeapon (player, e.weapon, item.netname);
179                         }
180                 }
181
182                 if((it = (item.items - (item.items & player.items) & IT_PICKUPMASK)))
183                 {
184                         pickedup = TRUE;
185                         player.items |= it;
186                 }
187
188                 if (item.strength_finished)
189                 {
190                         pickedup = TRUE;
191                         player.strength_finished = max(player.strength_finished, time) + cvar("g_balance_powerup_strength_time");
192                 }
193                 if (item.invincible_finished)
194                 {
195                         pickedup = TRUE;
196                         player.invincible_finished = max(player.invincible_finished, time) + cvar("g_balance_powerup_invincible_time");
197                 }
198                 //if (item.speed_finished)
199                 //{
200                 //      pickedup = TRUE;
201                 //      player.speed_finished = max(player.speed_finished, time) + cvar("g_balance_powerup_speed_time");
202                 //}
203                 //if (item.slowmo_finished)
204                 //{
205                 //      pickedup = TRUE;
206                 //      player.slowmo_finished = max(player.slowmo_finished, time) + (cvar("g_balance_powerup_slowmo_time") * cvar("g_balance_powerup_slowmo_speed"));
207                 //}
208
209                 if (item.health)
210                 if (player.health < item.max_health)
211                 {
212                         pickedup = TRUE;
213                         player.health = min(player.health + item.health, item.max_health);
214                         player.pauserothealth_finished = max(player.pauserothealth_finished, time + cvar("g_balance_pause_health_rot"));
215                 }
216                 if (item.armorvalue)
217                 if (player.armorvalue < item.max_armorvalue)
218                 {
219                         pickedup = TRUE;
220                         player.armorvalue = min(player.armorvalue + item.armorvalue, item.max_armorvalue);
221                         player.pauserotarmor_finished = max(player.pauserotarmor_finished, time + cvar("g_balance_pause_armor_rot"));
222                 }
223         }
224
225 :skip
226         // always eat teamed entities
227         if(item.team)
228                 pickedup = TRUE;
229
230         if (!pickedup)
231                 return 0;
232
233         sound (player, CHAN_AUTO, item.item_pickupsound, VOL_BASE, ATTN_NORM);
234         if (_switchweapon)
235                 W_SwitchWeapon_Force(player, w_getbestweapon(player));
236
237         return 1;
238 }
239
240 void Item_Touch (void)
241 {
242         entity e, head;
243
244         // remove the item if it's currnetly in a NODROP brush or hits a NOIMPACT surface (such as sky)
245         if (((trace_dpstartcontents | trace_dphitcontents) & DPCONTENTS_NODROP) || (trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT))
246         {
247                 remove(self);
248                 return;
249         }
250         if (other.classname != "player")
251                 return;
252         if (other.deadflag)
253                 return;
254         if (self.solid != SOLID_TRIGGER)
255                 return;
256         if (self.owner == other)
257                 return;
258
259         if(!Item_GiveTo(self, other))
260                 return;
261
262         if (self.classname == "droppedweapon")
263                 remove (self);
264         else if((self.flags & FL_WEAPON) && !(self.flags & FL_NO_WEAPON_STAY) && g_weapon_stay)
265                 return;
266         else
267         {
268                 self.solid = SOLID_NOT;
269                 self.model = string_null;
270                 if(self.team)
271                 {
272                         RandomSelection_Init();
273                         for(head = world; (head = findfloat(head, team, self.team)); ) if(head.flags & FL_ITEM)
274                                 RandomSelection_Add(head, 0, head.cnt, 0);
275                         e = RandomSelection_chosen_ent;
276                 }
277                 else
278                         e = self;
279                 e.nextthink = time + self.respawntime;
280                 e.think = Item_Respawn;
281         }
282 }
283
284 void Item_FindTeam()
285 {
286         entity head, e;
287
288         if(self.effects & EF_NODRAW)
289         {
290                 // marker for item team search
291                 dprint("Initializing item team ", ftos(self.team), "\n");
292                 RandomSelection_Init();
293                 for(head = world; (head = findfloat(head, team, self.team)); ) if(head.flags & FL_ITEM)
294                         RandomSelection_Add(head, 0, head.cnt, 0);
295                 e = RandomSelection_chosen_ent;
296                 e.state = 0;
297
298                 for(head = world; (head = findfloat(head, team, self.team)); ) if(head.flags & FL_ITEM)
299                 {
300                         if(head != e)
301                         {
302                                 // make it a non-spawned item
303                                 head.solid = SOLID_NOT;
304                                 head.model = string_null;
305                                 head.state = 1; // state 1 = initially hidden item
306                         }
307                         head.effects = head.effects - (head.effects & EF_NODRAW);
308                 }
309         }
310 }
311
312 void Item_Reset()
313 {
314         if(self.state == 1)
315         {
316                 self.model = string_null;
317                 self.solid = SOLID_NOT;
318         }
319         else
320         {
321                 self.model = self.mdl;
322                 self.solid = SOLID_TRIGGER;
323         }
324         setorigin (self, self.origin);
325         self.think = SUB_Null;
326         self.nextthink = 0;
327 }
328
329 // Savage: used for item garbage-collection
330 // TODO: perhaps nice special effect?
331 void RemoveItem(void)
332 {
333         remove(self);
334 }
335
336 // pickup evaluation functions
337 // these functions decide how desirable an item is to the bots
338
339 float generic_pickupevalfunc(entity player, entity item) {return item.bot_pickupbasevalue;};
340
341 float weapon_pickupevalfunc(entity player, entity item)
342 {
343         // if we already have the weapon, rate it 1/5th normal value
344         if ((player.weapons & item.weapons) == item.weapons)
345                 return item.bot_pickupbasevalue * 0.2;
346         return item.bot_pickupbasevalue;
347 };
348
349 float commodity_pickupevalfunc(entity player, entity item)
350 {
351         float c;
352         c = 0;
353         // TODO: figure out if the player even has the weapon this ammo is for?
354         // may not affect strategy much though...
355         // find out how much more ammo/armor/health the player can hold
356         if (item.ammo_shells)
357         if (player.ammo_shells < g_pickup_shells_max)
358                 c = c + max(0, 1 - player.ammo_shells / g_pickup_shells_max);
359         if (item.ammo_nails)
360         if (player.ammo_nails < g_pickup_nails_max)
361                 c = c + max(0, 1 - player.ammo_nails / g_pickup_nails_max);
362         if (item.ammo_rockets)
363         if (player.ammo_rockets < g_pickup_rockets_max)
364                 c = c + max(0, 1 - player.ammo_rockets / g_pickup_rockets_max);
365         if (item.ammo_cells)
366         if (player.ammo_cells < g_pickup_cells_max)
367                 c = c + max(0, 1 - player.ammo_cells / g_pickup_cells_max);
368         if (item.armorvalue)
369         if (player.armorvalue < item.max_armorvalue)
370                 c = c + max(0, 1 - player.armorvalue / item.max_armorvalue);
371         if (item.health)
372         if (player.health < item.max_health)
373                 c = c + max(0, 1 - player.health / item.max_health);
374
375         return item.bot_pickupbasevalue * c;
376 };
377
378
379 .float is_item;
380 void StartItem (string itemmodel, string pickupsound, float defaultrespawntime, string itemname, float itemid, float weaponid, float itemflags, float(entity player, entity item) pickupevalfunc, float pickupbasevalue)
381 {
382         startitem_failed = FALSE;
383
384         // is it a dropped weapon?
385         if (self.classname == "droppedweapon")
386         {
387                 self.reset = SUB_Remove;
388                 // it's a dropped weapon
389                 self.movetype = MOVETYPE_TOSS;
390                 self.solid = SOLID_TRIGGER;
391                 // Savage: remove thrown items after a certain period of time ("garbage collection")
392                 self.think = RemoveItem;
393                 self.nextthink = time + 60;
394                 // don't drop if in a NODROP zone (such as lava)
395                 traceline(self.origin, self.origin, MOVE_NORMAL, self);
396                 if (trace_dpstartcontents & DPCONTENTS_NODROP)
397                 {
398                         startitem_failed = TRUE;
399                         remove(self);
400                         return;
401                 }
402         }
403         else
404         {
405                 self.reset = Item_Reset;
406                 // it's a level item
407                 if(self.spawnflags & 1)
408                         self.noalign = 1;
409                 if (self.noalign)
410                         self.movetype = MOVETYPE_NONE;
411                 else
412                         self.movetype = MOVETYPE_TOSS;
413                 self.solid = SOLID_TRIGGER;
414                 // do item filtering according to game mode and other things
415                 if (!self.noalign)
416                 {
417                         // first nudge it off the floor a little bit to avoid math errors
418                         setorigin(self, self.origin + '0 0 1');
419                         // set item size before we spawn a spawnfunc_waypoint
420                         if((itemflags & FL_POWERUP) || self.health || self.armorvalue)
421                                 setsize (self, '-16 -16 0', '16 16 48');
422                         else
423                                 setsize (self, '-16 -16 0', '16 16 32');
424                         // note droptofloor returns FALSE if stuck/or would fall too far
425                         droptofloor();
426                         waypoint_spawnforitem(self);
427                 }
428
429                 if(teams_matter)
430                 {
431                         if(self.notteam)
432                         {
433                                 print("removed non-teamplay ", self.classname, "\n");
434                                 startitem_failed = TRUE;
435                                 remove (self);
436                                 return;
437                         }
438                 }
439                 else
440                 {
441                         if(self.notfree)
442                         {
443                                 print("removed non-FFA ", self.classname, "\n");
444                                 startitem_failed = TRUE;
445                                 remove (self);
446                                 return;
447                         }
448                 }
449
450                 if(self.notq3a)
451                 {
452                         // We aren't TA or something like that, so we keep the Q3A entities
453                         print("removed non-Q3A ", self.classname, "\n");
454                         startitem_failed = TRUE;
455                         remove (self);
456                         return;
457                 }
458
459                 /*
460                  * can't do it that way, as it would break maps
461                  * TODO make a target_give like entity another way, that perhaps has
462                  * the weapon name in a key
463                 if(self.targetname)
464                 {
465                         // target_give not yet supported; maybe later
466                         print("removed targeted ", self.classname, "\n");
467                         startitem_failed = TRUE;
468                         remove (self);
469                         return;
470                 }
471                 */
472
473                 if(cvar("spawn_debug") >= 2)
474                 {
475                         entity otheritem;
476                         for(otheritem = findradius(self.origin, 3); otheritem; otheritem = otheritem.chain)
477                         {
478                                 if(otheritem.is_item)
479                                 {
480                                         dprint("XXX Found duplicated item: ", itemname, vtos(self.origin));
481                                         dprint(" vs ", otheritem.netname, vtos(otheritem.origin), "\n");
482                                         error("Mapper sucks.");
483                                 }
484                         }
485                         self.is_item = TRUE;
486                 }
487
488                 weaponsInMap |= weaponid;
489
490                 if(g_lms)
491                 {
492                         startitem_failed = TRUE;
493                         remove(self);
494                         return;
495                 }
496                 else if (g_weaponarena && ((weaponid & WEPBIT_ALL) || (itemid & IT_AMMO)))
497                 {
498                         startitem_failed = TRUE;
499                         remove(self);
500                         return;
501                 }
502                 else if (g_minstagib)
503                 {
504                         // don't remove dropped items and powerups
505                         if (self.classname != "minstagib")
506                         {
507                                 startitem_failed = TRUE;
508                                 remove (self);
509                                 return;
510                         }
511                 }
512                 else if ((!cvar("g_pickup_items") || g_nixnex) && itemid != IT_STRENGTH && itemid != IT_INVINCIBLE && itemid != IT_HEALTH)
513                 {
514                         startitem_failed = TRUE;
515                         remove (self);
516                         return;
517                 }
518
519                 precache_model (itemmodel);
520                 precache_sound (pickupsound);
521                 precache_sound ("misc/itemrespawn.wav");
522
523                 if((itemid & (IT_STRENGTH | IT_INVINCIBLE | IT_HEALTH | IT_ARMOR | IT_KEY1 | IT_KEY2)) || (weaponid & WEPBIT_ALL))
524                         self.target = "###item###"; // for finding the nearest item using find()
525         }
526
527         self.bot_pickup = TRUE;
528         self.bot_pickupevalfunc = pickupevalfunc;
529         self.bot_pickupbasevalue = pickupbasevalue;
530         self.mdl = itemmodel;
531         self.item_pickupsound = pickupsound;
532         // let mappers override respawntime
533         if (!self.respawntime)
534                 self.respawntime = defaultrespawntime;
535         self.netname = itemname;
536         self.items = itemid;
537         self.weapons = weaponid;
538         self.flags = FL_ITEM | itemflags;
539         self.touch = Item_Touch;
540         setmodel (self, self.mdl); // precision set below
541         self.effects |= EF_LOWPRECISION;
542         if((itemflags & FL_POWERUP) || self.health || self.armorvalue)
543                 setsize (self, '-16 -16 0', '16 16 48');
544         else
545                 setsize (self, '-16 -16 0', '16 16 32');
546         if(itemflags & FL_WEAPON)
547                 self.modelflags |= MF_ROTATE;
548
549         if (self.classname != "droppedweapon") // if dropped, colormap is already set up nicely
550         if (itemflags & FL_WEAPON)
551         {
552                 // neutral team color for pickup weapons
553                 self.colormap = 1024; // color shirt=0 pants=0 grey
554         }
555
556         if (cvar("g_fullbrightitems"))
557                 self.effects = self.effects | EF_FULLBRIGHT;
558
559         self.state = 0;
560         if(self.team)
561         {
562                 if(!self.cnt)
563                         self.cnt = 1; // item probability weight
564                 self.effects = self.effects | EF_NODRAW; // marker for item team search
565                 InitializeEntity(self, Item_FindTeam, INITPRIO_FINDTARGET);
566         }
567 }
568
569 /* replace items in minstagib
570  * IT_STRENGTH   = invisibility
571  * IT_NAILS      = extra lives
572  * IT_INVINCIBLE = speed
573  */
574 void minstagib_items (float itemid)
575 {
576         // we don't want to replace dropped weapons ;)
577         if (self.classname == "droppedweapon")
578         {
579                 self.ammo_cells = 25;
580                 StartItem ("models/weapons/g_nex.md3",
581                         "weapons/weaponpickup.wav", 15,
582                         "MinstaNex", 0, WEPBIT_MINSTANEX, FL_WEAPON, generic_pickupevalfunc, 1000);
583                 return;
584         }
585
586         local float rnd;
587         self.classname = "minstagib";
588
589         // replace rocket launchers and nex guns with ammo cells
590         if (itemid == IT_CELLS)
591         {
592                 self.ammo_cells = 1;
593                 StartItem ("models/items/a_cells.md3",
594                         "misc/itempickup.wav", 45,
595                         "Nex Ammo", IT_CELLS, 0, 0, generic_pickupevalfunc, 100);
596                 return;
597         }
598
599         // randomize
600         rnd = random() * 3;
601         if (rnd <= 1)
602                 itemid = IT_STRENGTH;
603         else if (rnd <= 2)
604                 itemid = IT_NAILS;
605         else
606                 itemid = IT_INVINCIBLE;
607
608         // replace with invis
609         if (itemid == IT_STRENGTH)
610         {
611                 self.effects = EF_ADDITIVE;
612                 self.strength_finished = 30;
613                 StartItem ("models/items/g_strength.md3",
614                         "misc/powerup.wav", g_pickup_respawntime_powerup,
615                         "Invisibility", IT_STRENGTH, 0, FL_POWERUP, generic_pickupevalfunc, BOT_PICKUP_RATING_MID);
616         }
617         // replace with extra lives
618         if (itemid == IT_NAILS)
619         {
620                 self.max_health = 1;
621                 StartItem ("models/items/g_h100.md3",
622                         "misc/megahealth.wav", g_pickup_respawntime_powerup,
623                         "Extralife", IT_NAILS, 0, FL_POWERUP, generic_pickupevalfunc, BOT_PICKUP_RATING_HIGH);
624
625         }
626         // replace with speed
627         if (itemid == IT_INVINCIBLE)
628         {
629                 self.effects = EF_ADDITIVE;
630                 self.invincible_finished = 30;
631                 StartItem ("models/items/g_invincible.md3",
632                         "misc/powerup_shield.wav", g_pickup_respawntime_powerup,
633                         "Speed", IT_INVINCIBLE, 0, FL_POWERUP, generic_pickupevalfunc, BOT_PICKUP_RATING_MID);
634         }
635
636 }
637
638 float minst_no_auto_cells;
639 void minst_remove_item (void) {
640         if(minst_no_auto_cells)
641                 remove(self);
642 }
643
644 float weaponswapping;
645 float internalteam;
646
647 void weapon_defaultspawnfunc(float wpn)
648 {
649         entity e;
650         float t;
651         var .float ammofield;
652         string s;
653         entity oldself;
654         float i, j;
655
656         // set the respawntime in advance (so replaced weapons can copy it)
657         if(!self.respawntime)
658         {
659                 e = get_weaponinfo(wpn);
660                 if(e.items == IT_SUPERWEAPON)
661                         self.respawntime = g_pickup_respawntime_powerup;
662                 else
663                         self.respawntime = g_pickup_respawntime_weapon;
664         }
665
666         if(self.classname != "droppedweapon" && self.classname != "replacedweapon")
667         {
668                 e = get_weaponinfo(wpn);
669                 s = cvar_string(strcat("g_weaponreplace_", e.netname));
670                 if(s == "0")
671                 {
672                         remove(self);
673                         startitem_failed = TRUE;
674                         return;
675                 }
676                 t = tokenize_sane(s);
677                 if(t >= 2)
678                 {
679                         self.team = --internalteam;
680                         oldself = self;
681                         for(i = 1; i < t; ++i)
682                         {
683                                 s = argv(i);
684                                 for(j = WEP_FIRST; j <= WEP_LAST; ++j)
685                                 {
686                                         e = get_weaponinfo(j);
687                                         if(e.netname == s)
688                                         {
689                                                 self = spawn();
690                                                 copyentity(oldself, self);
691                                                 self.classname = "replacedweapon";
692                                                 weapon_defaultspawnfunc(j);
693                                                 break;
694                                         }
695                                 }
696                                 if(j > WEP_LAST)
697                                 {
698                                         print("The weapon replace list for ", oldself.classname, " contains an unknown weapon ", s, ". Skipped.\n");
699                                 }
700                         }
701                         self = oldself;
702                 }
703                 if(t >= 1)
704                 {
705                         s = argv(0);
706                         wpn = 0;
707                         for(j = WEP_FIRST; j <= WEP_LAST; ++j)
708                         {
709                                 e = get_weaponinfo(j);
710                                 if(e.netname == s)
711                                 {
712                                         wpn = j;
713                                         break;
714                                 }
715                         }
716                         if(j > WEP_LAST)
717                         {
718                                 print("The weapon replace list for ", self.classname, " contains an unknown weapon ", s, ". Skipped.\n");
719                         }
720                 }
721                 if(wpn == 0)
722                 {
723                         remove(self);
724                         startitem_failed = TRUE;
725                         return;
726                 }
727         }
728
729         e = get_weaponinfo(wpn);
730
731         if(e.items && e.items != IT_SUPERWEAPON)
732         {
733                 ammofield = Item_CounterField(e.items);
734                 if(!self.ammofield)
735                         self.ammofield = cvar(strcat("g_pickup_", Item_CounterFieldName(e.items)));
736         }
737         else
738         {
739                 self.flags |= FL_NO_WEAPON_STAY;
740         }
741
742         // weapon stay isn't supported for teamed weapons
743         if(self.team)
744                 self.flags |= FL_NO_WEAPON_STAY;
745
746         if(g_weapon_stay == 2 && self.classname != "droppedweapon")
747         {
748                 self.ammo_shells = 0;
749                 self.ammo_nails = 0;
750                 self.ammo_cells = 0;
751                 self.ammo_rockets = 0;
752                 // weapon stay 2: don't use ammo on weapon pickups; instead
753                 // initialize all ammo types to the pickup ammo unless set by g_start_ammo_*
754         }
755
756         StartItem(e.model, "weapons/weaponpickup.wav", self.respawntime, e.message, 0, e.weapons, FL_WEAPON, weapon_pickupevalfunc, e.bot_pickupbasevalue);
757         if (self.modelindex) // don't precache if self was removed
758                 weapon_action(e.weapon, WR_PRECACHE);
759 }
760
761 void spawnfunc_weapon_shotgun (void);
762 void spawnfunc_weapon_uzi (void) {
763         if(q3acompat_machineshotgunswap)
764         if(self.classname != "droppedweapon")
765         {
766                 weapon_defaultspawnfunc(WEP_SHOTGUN);
767                 return;
768         }
769         weapon_defaultspawnfunc(WEP_UZI);
770 }
771
772 void spawnfunc_weapon_shotgun (void) {
773         if(q3acompat_machineshotgunswap)
774         if(self.classname != "droppedweapon")
775         {
776                 weapon_defaultspawnfunc(WEP_UZI);
777                 return;
778         }
779         weapon_defaultspawnfunc(WEP_SHOTGUN);
780 }
781
782 void spawnfunc_weapon_nex (void)
783 {
784         if (g_minstagib)
785         {
786                 minstagib_items(IT_CELLS);
787                 self.think = minst_remove_item;
788                 self.nextthink = time;
789                 return;
790         }
791         weapon_defaultspawnfunc(WEP_NEX);
792 }
793
794 void spawnfunc_weapon_minstanex (void)
795 {
796         if (g_minstagib)
797         {
798                 minstagib_items(IT_CELLS);
799                 self.think = minst_remove_item;
800                 self.nextthink = time;
801                 return;
802         }
803         weapon_defaultspawnfunc(WEP_MINSTANEX);
804 }
805
806 void spawnfunc_weapon_rocketlauncher (void)
807 {
808         if (g_minstagib)
809         {
810                 minstagib_items(IT_CELLS);
811                 self.think = minst_remove_item;
812                 self.nextthink = time;
813                 return;
814         }
815         weapon_defaultspawnfunc(WEP_ROCKET_LAUNCHER);
816 }
817
818 void spawnfunc_item_rockets (void) {
819         if(!self.ammo_rockets)
820                 self.ammo_rockets = g_pickup_rockets;
821         StartItem ("models/items/a_rockets.md3", "misc/itempickup.wav", g_pickup_respawntime_ammo, "rockets", IT_ROCKETS, 0, 0, commodity_pickupevalfunc, 3000);
822 }
823
824 void spawnfunc_item_shells (void);
825 void spawnfunc_item_bullets (void) {
826         if(!weaponswapping)
827         if(q3acompat_machineshotgunswap)
828         if(self.classname != "droppedweapon")
829         {
830                 weaponswapping = TRUE;
831                 spawnfunc_item_shells();
832                 weaponswapping = FALSE;
833                 return;
834         }
835
836         if(!self.ammo_nails)
837                 self.ammo_nails = g_pickup_nails;
838         StartItem ("models/items/a_bullets.mdl", "misc/itempickup.wav", g_pickup_respawntime_ammo, "bullets", IT_NAILS, 0, 0, commodity_pickupevalfunc, 2000);
839 }
840
841 void spawnfunc_item_cells (void) {
842         if(!self.ammo_cells)
843                 self.ammo_cells = g_pickup_cells;
844         StartItem ("models/items/a_cells.md3", "misc/itempickup.wav", g_pickup_respawntime_ammo, "cells", IT_CELLS, 0, 0, commodity_pickupevalfunc, 2000);
845 }
846
847 void spawnfunc_item_shells (void) {
848         if(!weaponswapping)
849         if(q3acompat_machineshotgunswap)
850         if(self.classname != "droppedweapon")
851         {
852                 weaponswapping = TRUE;
853                 spawnfunc_item_bullets();
854                 weaponswapping = FALSE;
855                 return;
856         }
857
858         if(!self.ammo_shells)
859                 self.ammo_shells = g_pickup_shells;
860         StartItem ("models/items/a_shells.md3", "misc/itempickup.wav", g_pickup_respawntime_ammo, "shells", IT_SHELLS, 0, 0, commodity_pickupevalfunc, 500);
861 }
862
863 void spawnfunc_item_armor_small (void) {
864         if(!self.armorvalue)
865                 self.armorvalue = g_pickup_armorsmall;
866         if(!self.max_armorvalue)
867                 self.max_armorvalue = g_pickup_armorsmall_max;
868         StartItem ("models/items/g_a1.md3", "misc/armor1.wav", g_pickup_respawntime_short, "5 Armor", IT_ARMOR_SHARD, 0, 0, commodity_pickupevalfunc, BOT_PICKUP_RATING_LOW);
869 }
870
871 void spawnfunc_item_armor_medium (void) {
872         if(!self.armorvalue)
873                 self.armorvalue = g_pickup_armormedium;
874         if(!self.max_armorvalue)
875                 self.max_armorvalue = g_pickup_armormedium_max;
876         StartItem ("models/items/g_armormedium.md3", "misc/armor10.wav", g_pickup_respawntime_medium, "25 Armor", IT_ARMOR, 0, 0, commodity_pickupevalfunc, BOT_PICKUP_RATING_MID);
877 }
878
879 void spawnfunc_item_armor_big (void) {
880         if(!self.armorvalue)
881                 self.armorvalue = g_pickup_armorbig;
882         if(!self.max_armorvalue)
883                 self.max_armorvalue = g_pickup_armorbig_max;
884         StartItem ("models/items/g_a50.md3", "misc/armor17_5.wav", g_pickup_respawntime_long, "50 Armor", IT_ARMOR, 0, 0, commodity_pickupevalfunc, 20000);
885 }
886
887 void spawnfunc_item_armor_large (void) {
888         if(!self.armorvalue)
889                 self.armorvalue = g_pickup_armorlarge;
890         if(!self.max_armorvalue)
891                 self.max_armorvalue = g_pickup_armorlarge_max;
892         StartItem ("models/items/g_a25.md3", "misc/armor25.wav", g_pickup_respawntime_long, "100 Armor", IT_ARMOR, 0, 0, commodity_pickupevalfunc, BOT_PICKUP_RATING_HIGH);
893 }
894
895 void spawnfunc_item_health_small (void) {
896         if(!self.max_health)
897                 self.max_health = g_pickup_healthsmall_max;
898         if(!self.health)
899                 self.health = g_pickup_healthsmall;
900         StartItem ("models/items/g_h1.md3", "misc/minihealth.wav", g_pickup_respawntime_short, "5 Health", IT_5HP, 0, 0, commodity_pickupevalfunc, BOT_PICKUP_RATING_LOW);
901 }
902
903 void spawnfunc_item_health_medium (void) {
904         if(!self.max_health)
905                 self.max_health = g_pickup_healthmedium_max;
906         if(!self.health)
907                 self.health = g_pickup_healthmedium;
908         StartItem ("models/items/g_h25.md3", "misc/mediumhealth.wav", g_pickup_respawntime_short, "25 Health", IT_25HP, 0, 0, commodity_pickupevalfunc, BOT_PICKUP_RATING_MID);
909 }
910
911 void spawnfunc_item_health_large (void) {
912         if(!self.max_health)
913                 self.max_health = g_pickup_healthlarge_max;
914         if(!self.health)
915                 self.health = g_pickup_healthlarge;
916         StartItem ("models/items/g_h50.md3", "misc/mediumhealth.wav", g_pickup_respawntime_medium, "50 Health", IT_25HP, 0, 0, commodity_pickupevalfunc, BOT_PICKUP_RATING_MID);
917 }
918
919 void spawnfunc_item_health_mega (void) {
920         if(!cvar("g_powerup_superhealth"))
921                 return;
922
923         if(g_arena && !cvar("g_arena_powerups"))
924                 return;
925
926         if(g_minstagib) {
927                 minstagib_items(IT_NAILS);
928         } else {
929                 if(!self.max_health)
930                         self.max_health = g_pickup_healthmega_max;
931                 if(!self.health)
932                         self.health = g_pickup_healthmega;
933                 StartItem ("models/items/g_h100.md3", "misc/megahealth.wav", g_pickup_respawntime_long, "100 Health", IT_HEALTH, 0, 0, commodity_pickupevalfunc, BOT_PICKUP_RATING_HIGH);
934         }
935 }
936
937 // support old misnamed entities
938 void spawnfunc_item_armor1() { spawnfunc_item_armor_small(); }  // FIXME: in Quake this is green armor, in Nexuiz maps it is an armor shard
939 void spawnfunc_item_armor25() { spawnfunc_item_armor_large(); }
940 void spawnfunc_item_health1() { spawnfunc_item_health_small(); }
941 void spawnfunc_item_health25() { spawnfunc_item_health_medium(); }
942 void spawnfunc_item_health100() { spawnfunc_item_health_mega(); }
943
944 void spawnfunc_item_strength (void) {
945         if(!cvar("g_powerup_strength"))
946                 return;
947
948         if(g_arena && !cvar("g_arena_powerups"))
949                 return;
950
951         if(g_minstagib) {
952                 minstagib_items(IT_STRENGTH);
953         } else {
954                 precache_sound("weapons/strength_fire.wav");
955                 self.strength_finished = 30;
956                 self.effects = EF_ADDITIVE;
957                 StartItem ("models/items/g_strength.md3", "misc/powerup.wav", g_pickup_respawntime_powerup, "Strength Powerup", IT_STRENGTH, 0, FL_POWERUP, generic_pickupevalfunc, 100000);
958         }
959 }
960
961 void spawnfunc_item_invincible (void) {
962         if(!cvar("g_powerup_shield"))
963                 return;
964
965         if(g_arena && !cvar("g_arena_powerups"))
966                 return;
967
968         if(g_minstagib) {
969                 minstagib_items(IT_INVINCIBLE);
970         } else {
971                 self.invincible_finished = 30;
972                 self.effects = EF_ADDITIVE;
973                 StartItem ("models/items/g_invincible.md3", "misc/powerup_shield.wav", g_pickup_respawntime_powerup, "Invulnerability", IT_INVINCIBLE, 0, FL_POWERUP, generic_pickupevalfunc, 100000);
974         }
975 }
976
977 void spawnfunc_item_minst_cells (void) {
978         if (g_minstagib)
979         {
980                 minst_no_auto_cells = 1;
981                 minstagib_items(IT_CELLS);
982         }
983         else
984                 remove(self);
985 }
986
987 // compatibility:
988 void spawnfunc_item_quad (void) {self.classname = "item_strength";spawnfunc_item_strength();}
989
990 void spawnfunc_misc_models (void)
991 {
992         // exists as alias name for 2.4.2 compat
993         SetBrushEntityModel();
994 }
995
996 void spawnfunc_func_static (void)
997 {
998         // exists as alias name for having it with brushes
999         SetBrushEntityModel();
1000 }
1001
1002 void func_wall_use (void)
1003 {
1004         if(teams_matter)
1005         {
1006                 if(activator.team)
1007                         self.colormap = (activator.team - 1) * 0x11;
1008                 else
1009                         self.colormap = 0x00;
1010         }
1011         else
1012                 self.colormap = floor(random() * 256);
1013         self.colormap |= 1024; // RENDER_COLORMAPPED
1014 }
1015
1016 void spawnfunc_func_wall (void)
1017 {
1018         SetBrushEntityModel();
1019         if(!self.solid)
1020                 self.solid = SOLID_BSP;
1021         self.use = func_wall_use;
1022 }
1023
1024 void spawnfunc_func_illusionary (void)
1025 {
1026         SetBrushEntityModel();
1027         self.use = func_wall_use;
1028 }
1029
1030 void gamemodel_drop()
1031 {
1032         if(self.spawnflags & 3 == 1) // ALIGN_ORIGIN
1033         {
1034                 traceline(self.origin, self.origin - '0 0 4096', MOVE_NOMONSTERS, self);
1035                 setorigin(self, trace_endpos);
1036         }
1037         else if(self.spawnflags & 3 == 2) // ALIGN_BOTTOM
1038         {
1039                 tracebox(self.origin, self.mins, self.maxs, self.origin - '0 0 4096', MOVE_NOMONSTERS, self);
1040                 setorigin(self, trace_endpos);
1041         }
1042         else if(self.spawnflags & 3 == 3) // ALIGN_ORIGIN | ALIGN_BOTTOM
1043         {
1044                 traceline(self.origin, self.origin - '0 0 4096', MOVE_NOMONSTERS, self);
1045                 setorigin(self, trace_endpos - '0 0 1' * self.mins_z);
1046         }
1047 }
1048
1049 .float modelscale;
1050 void spawnfunc_misc_gamemodel (void)
1051 {
1052         if(!self.scale)
1053                 self.scale = self.modelscale;
1054         SetBrushEntityModel();
1055         self.use = func_wall_use;
1056
1057         InitializeEntity(self, gamemodel_drop, INITPRIO_DROPTOFLOOR);
1058 }
1059
1060 float target_item_func_set(float a, float b)
1061 {
1062         if(b == 0)
1063                 return a;
1064         else if(b < 0)
1065                 return 0;
1066         else
1067                 return b;
1068 }
1069
1070 float target_item_func_min(float a, float b)
1071 {
1072         if(b == 0)
1073                 return a;
1074         else if(b < 0)
1075                 return 0;
1076         else
1077                 return min(a, b);
1078 }
1079
1080 float target_item_func_max(float a, float b)
1081 {
1082         return max(a, b);
1083 }
1084
1085 float target_item_func_bitset(float a, float b)
1086 {
1087         return b;
1088 }
1089
1090 float target_item_func_and(float a, float b)
1091 {
1092         return a & b;
1093 }
1094
1095 float target_item_func_itembitset(float a, float b)
1096 {
1097         return (a - (a & (IT_UNLIMITED_WEAPON_AMMO | IT_STRENGTH | IT_INVINCIBLE))) | b;
1098 }
1099
1100 float target_item_func_itemand(float a, float b)
1101 {
1102         return (a - (a & (IT_UNLIMITED_WEAPON_AMMO | IT_STRENGTH | IT_INVINCIBLE))) | (a & b);
1103 }
1104
1105 float target_item_func_or(float a, float b)
1106 {
1107         return a | b;
1108 }
1109
1110 float target_item_func_andnot(float a, float b)
1111 {
1112         return a - (a & b);
1113 }
1114
1115 float target_item_changed;
1116 void target_item_change(float binary, .float field, float(float a, float b) func, string sound_increase, string sound_decrease)
1117 {
1118         float n, d;
1119         n = func(activator.field, self.field);
1120
1121         if(binary)
1122         {
1123                 d = n & activator.field;
1124                 if(d != n) // bits added?
1125                         d = +1;
1126                 else if(d != activator.field) // bits removed?
1127                         d = -1;
1128                 else
1129                         d = 0;
1130         }
1131         else
1132                 d = n - activator.field;
1133
1134         if(d < 0)
1135         {
1136                 if(sound_decrease != "")
1137                         sound (activator, CHAN_AUTO, sound_decrease, VOL_BASE, ATTN_NORM);
1138                 target_item_changed = 1;
1139         }
1140         else if(d > 0)
1141         {
1142                 if(sound_increase != "")
1143                         sound (activator, CHAN_AUTO, sound_increase, VOL_BASE, ATTN_NORM);
1144                 target_item_changed = 1;
1145         }
1146         activator.field = n;
1147 }
1148
1149 void target_items_use (void)
1150 {
1151         float h0, a0;
1152         if(activator.classname != "player")
1153                 return;
1154         if(activator.deadflag != DEAD_NO)
1155                 return;
1156         EXACTTRIGGER_TOUCH;
1157
1158         entity e;
1159         for(e = world; (e = find(e, classname, "droppedweapon")); )
1160                 if(e.enemy == activator)
1161                         remove(e);
1162
1163         float _switchweapon;
1164         _switchweapon = FALSE;
1165         if (activator.autoswitch)
1166                 if (activator.switchweapon == w_getbestweapon(activator))
1167                         _switchweapon = TRUE;
1168
1169         a0 = activator.armorvalue;
1170         h0 = activator.health;
1171         target_item_changed = 0;
1172
1173         if(self.spawnflags == 0) // SET
1174         {
1175                 target_item_change(0, ammo_shells, target_item_func_set, "misc/itempickup.wav", "");
1176                 target_item_change(0, ammo_nails, target_item_func_set, "misc/itempickup.wav", "");
1177                 target_item_change(0, ammo_rockets, target_item_func_set, "misc/itempickup.wav", "");
1178                 target_item_change(0, ammo_cells, target_item_func_set, "misc/itempickup.wav", "");
1179                 target_item_change(0, ammo_fuel, target_item_func_set, "misc/itempickup.wav", "");
1180                 target_item_change(0, health, target_item_func_set, "misc/megahealth.wav", "");
1181                 target_item_change(0, armorvalue, target_item_func_set, "misc/armor25.wav", "");
1182                 target_item_change(1, items, target_item_func_itembitset, "misc/powerup.wav", "");
1183                 target_item_change(1, weapons, target_item_func_bitset, "weapons/weaponpickup.wav", "");
1184
1185                 if((self.items & activator.items) & IT_STRENGTH)
1186                         activator.strength_finished = time + self.strength_finished;
1187                 if((self.items & activator.items) & IT_INVINCIBLE)
1188                         activator.invincible_finished = time + self.invincible_finished;
1189         }
1190         else if(self.spawnflags == 1) // AND/MIN
1191         {
1192                 target_item_change(0, ammo_shells, target_item_func_min, "misc/itempickup.wav", "");
1193                 target_item_change(0, ammo_nails, target_item_func_min, "misc/itempickup.wav", "");
1194                 target_item_change(0, ammo_rockets, target_item_func_min, "misc/itempickup.wav", "");
1195                 target_item_change(0, ammo_cells, target_item_func_min, "misc/itempickup.wav", "");
1196                 target_item_change(0, ammo_fuel, target_item_func_min, "misc/itempickup.wav", "");
1197                 target_item_change(0, health, target_item_func_min, "misc/megahealth.wav", "");
1198                 target_item_change(0, armorvalue, target_item_func_min, "misc/armor25.wav", "");
1199                 target_item_change(1, items, target_item_func_itemand, "misc/powerup.wav", "");
1200                 target_item_change(1, weapons, target_item_func_and, "weapons/weaponpickup.wav", "");
1201
1202                 if((self.items & activator.items) & IT_STRENGTH)
1203                         activator.strength_finished = min(activator.strength_finished, time + self.strength_finished);
1204                 if((self.items & activator.items) & IT_INVINCIBLE)
1205                         activator.invincible_finished = min(activator.invincible_finished, time + self.invincible_finished);
1206         }
1207         else if(self.spawnflags == 2) // OR/MAX
1208         {
1209                 target_item_change(0, ammo_shells, target_item_func_max, "misc/itempickup.wav", "");
1210                 target_item_change(0, ammo_nails, target_item_func_max, "misc/itempickup.wav", "");
1211                 target_item_change(0, ammo_rockets, target_item_func_max, "misc/itempickup.wav", "");
1212                 target_item_change(0, ammo_cells, target_item_func_max, "misc/itempickup.wav", "");
1213                 target_item_change(0, ammo_fuel, target_item_func_max, "misc/itempickup.wav", "");
1214                 target_item_change(0, health, target_item_func_max, "misc/megahealth.wav", "");
1215                 target_item_change(0, armorvalue, target_item_func_max, "misc/armor25.wav", "");
1216                 target_item_change(1, items, target_item_func_or, "misc/powerup.wav", "");
1217                 target_item_change(1, weapons, target_item_func_or, "weapons/weaponpickup.wav", "");
1218
1219                 if((self.items & activator.items) & IT_STRENGTH)
1220                         activator.strength_finished = max(activator.strength_finished, time + self.strength_finished);
1221                 if((self.items & activator.items) & IT_INVINCIBLE)
1222                         activator.invincible_finished = max(activator.invincible_finished, time + self.invincible_finished);
1223         }
1224         else if(self.spawnflags == 4) // ANDNOT/MIN
1225         {
1226                 target_item_change(0, ammo_shells, target_item_func_min, "misc/itempickup.wav", "");
1227                 target_item_change(0, ammo_nails, target_item_func_min, "misc/itempickup.wav", "");
1228                 target_item_change(0, ammo_rockets, target_item_func_min, "misc/itempickup.wav", "");
1229                 target_item_change(0, ammo_cells, target_item_func_min, "misc/itempickup.wav", "");
1230                 target_item_change(0, ammo_fuel, target_item_func_min, "misc/itempickup.wav", "");
1231                 target_item_change(0, health, target_item_func_min, "misc/megahealth.wav", "");
1232                 target_item_change(0, armorvalue, target_item_func_min, "misc/armor25.wav", "");
1233                 target_item_change(1, items, target_item_func_andnot, "misc/powerup.wav", "");
1234                 target_item_change(1, weapons, target_item_func_andnot, "weapons/weaponpickup.wav", "");
1235
1236                 if((self.items & activator.items) & IT_STRENGTH)
1237                         activator.strength_finished = min(activator.strength_finished, time + self.strength_finished);
1238                 if((self.items & activator.items) & IT_INVINCIBLE)
1239                         activator.invincible_finished = min(activator.invincible_finished, time + self.invincible_finished);
1240         }
1241
1242         if not(activator.items & IT_STRENGTH)
1243                 activator.strength_finished = 0;
1244         if not(activator.items & IT_INVINCIBLE)
1245                 activator.invincible_finished = 0;
1246
1247         if(activator.health > h0)
1248                 activator.pauserothealth_finished = max(activator.pauserothealth_finished, time + cvar("g_balance_pause_health_rot"));
1249         else if(activator.health < h0)
1250                 activator.pauseregen_finished = max(activator.pauseregen_finished, time + cvar("g_balance_pause_health_regen"));
1251
1252         if(activator.armorvalue > a0)
1253                 activator.pauserotarmor_finished = max(activator.pauserothealth_finished, time + cvar("g_balance_pause_health_rot"));
1254
1255         if not(activator.weapons & W_WeaponBit(activator.switchweapon))
1256                 _switchweapon = TRUE;
1257         if(_switchweapon)
1258                 W_SwitchWeapon_Force(activator, w_getbestweapon(activator));
1259
1260         if(target_item_changed)
1261                 centerprint(activator, self.message);
1262 }
1263
1264 void spawnfunc_target_items (void)
1265 {
1266         float n, i, j;
1267         entity e;
1268         self.use = target_items_use;
1269         if(!self.strength_finished)
1270                 self.strength_finished = cvar("g_balance_powerup_strength_time");
1271         if(!self.invincible_finished)
1272                 self.invincible_finished = cvar("g_balance_powerup_invincible_time");
1273
1274         precache_sound("misc/itempickup.wav");
1275         precache_sound("misc/itempickup.wav");
1276         precache_sound("misc/itempickup.wav");
1277         precache_sound("misc/itempickup.wav");
1278         precache_sound("misc/megahealth.wav");
1279         precache_sound("misc/armor25.wav");
1280         precache_sound("misc/powerup.wav");
1281         precache_sound("weapons/weaponpickup.wav");
1282
1283         n = tokenize_sane(self.netname);
1284         for(i = 0; i < n; ++i)
1285         {
1286                 if(argv(i) == "unlimited_ammo")         self.items |= IT_UNLIMITED_AMMO;
1287                 if(argv(i) == "unlimited_weapon_ammo")  self.items |= IT_UNLIMITED_WEAPON_AMMO;
1288                 if(argv(i) == "unlimited_superweapons") self.items |= IT_UNLIMITED_SUPERWEAPONS;
1289                 if(argv(i) == "strength")               self.items |= IT_STRENGTH;
1290                 if(argv(i) == "invincible")             self.items |= IT_INVINCIBLE;
1291                 if(argv(i) == "jetpack")                self.items |= IT_JETPACK;
1292                 if(argv(i) == "fuel_regen")             self.items |= IT_FUEL_REGEN;
1293                 for(j = WEP_FIRST; j <= WEP_LAST; ++j)
1294                 {
1295                         e = get_weaponinfo(j);
1296                         if(argv(i) == e.netname)
1297                         {
1298                                 self.weapons |= e.weapons;
1299                                 if(self.spawnflags == 0 || self.spawnflags == 2)
1300                                         weapon_action(e.weapon, WR_PRECACHE);
1301                         }
1302                 }
1303         }
1304 }