1 /*
2 Copyright (C) 1997-2001 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19 */
20 #include "g_local.h"
21
22
23 qboolean Pickup_Weapon (edict_t *ent, edict_t *other);
24 void Use_Weapon (edict_t *ent, gitem_t *inv);
25 void Drop_Weapon (edict_t *ent, gitem_t *inv);
26
27 void Weapon_Blaster (edict_t *ent);
28 void Weapon_Shotgun (edict_t *ent);
29 void Weapon_SuperShotgun (edict_t *ent);
30 void Weapon_Machinegun (edict_t *ent);
31 void Weapon_Chaingun (edict_t *ent);
32 void Weapon_HyperBlaster (edict_t *ent);
33 void Weapon_RocketLauncher (edict_t *ent);
34 void Weapon_Grenade (edict_t *ent);
35 void Weapon_GrenadeLauncher (edict_t *ent);
36 void Weapon_Railgun (edict_t *ent);
37 void Weapon_BFG (edict_t *ent);
38
39 gitem_armor_t jacketarmor_info = { 25, 50, .30, .00, ARMOR_JACKET};
40 gitem_armor_t combatarmor_info = { 50, 100, .60, .30, ARMOR_COMBAT};
41 gitem_armor_t bodyarmor_info = {100, 200, .80, .60, ARMOR_BODY};
42
43 int jacket_armor_index;
44 int combat_armor_index;
45 int body_armor_index;
46 static int power_screen_index;
47 static int power_shield_index;
48
49 #define HEALTH_IGNORE_MAX 1
50 #define HEALTH_TIMED 2
51
52 void Use_Quad (edict_t *ent, gitem_t *item);
53 static int quad_drop_timeout_hack;
54
55 //======================================================================
56
57 /*
58 ===============
59 GetItemByIndex
60 ===============
61 */
GetItemByIndex(int index)62 gitem_t *GetItemByIndex (int index)
63 {
64 if (index == 0 || index >= game.num_items)
65 return NULL;
66
67 return &itemlist[index];
68 }
69
70
71 /*
72 ===============
73 FindItemByClassname
74
75 ===============
76 */
FindItemByClassname(char * classname)77 gitem_t *FindItemByClassname (char *classname)
78 {
79 int i;
80 gitem_t *it;
81
82 it = itemlist;
83 for (i=0 ; i<game.num_items ; i++, it++)
84 {
85 if (!it->classname)
86 continue;
87 if (!Q_stricmp(it->classname, classname))
88 return it;
89 }
90
91 return NULL;
92 }
93
94 /*
95 ===============
96 FindItem
97
98 ===============
99 */
FindItem(char * pickup_name)100 gitem_t *FindItem (char *pickup_name)
101 {
102 int i;
103 gitem_t *it;
104
105 it = itemlist;
106 for (i=0 ; i<game.num_items ; i++, it++)
107 {
108 if (!it->pickup_name)
109 continue;
110 if (!Q_stricmp(it->pickup_name, pickup_name))
111 return it;
112 }
113
114 return NULL;
115 }
116
117 //======================================================================
118
DoRespawn(edict_t * ent)119 void DoRespawn (edict_t *ent)
120 {
121 if (ent->team)
122 {
123 edict_t *master;
124 int count;
125 int choice;
126
127 master = ent->teammaster;
128
129 for (count = 0, ent = master; ent; ent = ent->chain, count++)
130 ;
131
132 choice = rand() % count;
133
134 for (count = 0, ent = master; count < choice; ent = ent->chain, count++)
135 ;
136 }
137
138 ent->svflags &= ~SVF_NOCLIENT;
139 ent->solid = SOLID_TRIGGER;
140 gi.linkentity (ent);
141
142 // send an effect
143 ent->s.event = EV_ITEM_RESPAWN;
144 }
145
SetRespawn(edict_t * ent,float delay)146 void SetRespawn (edict_t *ent, float delay)
147 {
148 ent->flags |= FL_RESPAWN;
149 ent->svflags |= SVF_NOCLIENT;
150 ent->solid = SOLID_NOT;
151 ent->nextthink = level.time + delay;
152 ent->think = DoRespawn;
153 gi.linkentity (ent);
154 }
155
156
157 //======================================================================
158
Pickup_Powerup(edict_t * ent,edict_t * other)159 qboolean Pickup_Powerup (edict_t *ent, edict_t *other)
160 {
161 int quantity;
162
163 quantity = other->client->pers.inventory[ITEM_INDEX(ent->item)];
164 if ((skill->value == 1 && quantity >= 2) || (skill->value >= 2 && quantity >= 1))
165 return false;
166
167 if ((coop->value) && (ent->item->flags & IT_STAY_COOP) && (quantity > 0))
168 return false;
169
170 other->client->pers.inventory[ITEM_INDEX(ent->item)]++;
171
172 if (deathmatch->value)
173 {
174 if (!(ent->spawnflags & DROPPED_ITEM) )
175 SetRespawn (ent, ent->item->quantity);
176 if (((int)dmflags->value & DF_INSTANT_ITEMS) || ((ent->item->use == Use_Quad) && (ent->spawnflags & DROPPED_PLAYER_ITEM)))
177 {
178 if ((ent->item->use == Use_Quad) && (ent->spawnflags & DROPPED_PLAYER_ITEM))
179 quad_drop_timeout_hack = (ent->nextthink - level.time) / FRAMETIME;
180 ent->item->use (other, ent->item);
181 }
182 }
183
184 return true;
185 }
186
Drop_General(edict_t * ent,gitem_t * item)187 void Drop_General (edict_t *ent, gitem_t *item)
188 {
189 Drop_Item (ent, item);
190 ent->client->pers.inventory[ITEM_INDEX(item)]--;
191 ValidateSelectedItem (ent);
192 }
193
194
195 //======================================================================
196
Pickup_Adrenaline(edict_t * ent,edict_t * other)197 qboolean Pickup_Adrenaline (edict_t *ent, edict_t *other)
198 {
199 if (!deathmatch->value)
200 other->max_health += 1;
201
202 if (other->health < other->max_health)
203 other->health = other->max_health;
204
205 if (!(ent->spawnflags & DROPPED_ITEM) && (deathmatch->value))
206 SetRespawn (ent, ent->item->quantity);
207
208 return true;
209 }
210
Pickup_AncientHead(edict_t * ent,edict_t * other)211 qboolean Pickup_AncientHead (edict_t *ent, edict_t *other)
212 {
213 other->max_health += 2;
214
215 if (!(ent->spawnflags & DROPPED_ITEM) && (deathmatch->value))
216 SetRespawn (ent, ent->item->quantity);
217
218 return true;
219 }
220
Pickup_Bandolier(edict_t * ent,edict_t * other)221 qboolean Pickup_Bandolier (edict_t *ent, edict_t *other)
222 {
223 gitem_t *item;
224 int index;
225
226 if (other->client->pers.max_bullets < 250)
227 other->client->pers.max_bullets = 250;
228 if (other->client->pers.max_shells < 150)
229 other->client->pers.max_shells = 150;
230 if (other->client->pers.max_cells < 250)
231 other->client->pers.max_cells = 250;
232 if (other->client->pers.max_slugs < 75)
233 other->client->pers.max_slugs = 75;
234
235 item = FindItem("Bullets");
236 if (item)
237 {
238 index = ITEM_INDEX(item);
239 other->client->pers.inventory[index] += item->quantity;
240 if (other->client->pers.inventory[index] > other->client->pers.max_bullets)
241 other->client->pers.inventory[index] = other->client->pers.max_bullets;
242 }
243
244 item = FindItem("Shells");
245 if (item)
246 {
247 index = ITEM_INDEX(item);
248 other->client->pers.inventory[index] += item->quantity;
249 if (other->client->pers.inventory[index] > other->client->pers.max_shells)
250 other->client->pers.inventory[index] = other->client->pers.max_shells;
251 }
252
253 if (!(ent->spawnflags & DROPPED_ITEM) && (deathmatch->value))
254 SetRespawn (ent, ent->item->quantity);
255
256 return true;
257 }
258
Pickup_Pack(edict_t * ent,edict_t * other)259 qboolean Pickup_Pack (edict_t *ent, edict_t *other)
260 {
261 gitem_t *item;
262 int index;
263
264 if (other->client->pers.max_bullets < 300)
265 other->client->pers.max_bullets = 300;
266 if (other->client->pers.max_shells < 200)
267 other->client->pers.max_shells = 200;
268 if (other->client->pers.max_rockets < 100)
269 other->client->pers.max_rockets = 100;
270 if (other->client->pers.max_grenades < 100)
271 other->client->pers.max_grenades = 100;
272 if (other->client->pers.max_cells < 300)
273 other->client->pers.max_cells = 300;
274 if (other->client->pers.max_slugs < 100)
275 other->client->pers.max_slugs = 100;
276
277 item = FindItem("Bullets");
278 if (item)
279 {
280 index = ITEM_INDEX(item);
281 other->client->pers.inventory[index] += item->quantity;
282 if (other->client->pers.inventory[index] > other->client->pers.max_bullets)
283 other->client->pers.inventory[index] = other->client->pers.max_bullets;
284 }
285
286 item = FindItem("Shells");
287 if (item)
288 {
289 index = ITEM_INDEX(item);
290 other->client->pers.inventory[index] += item->quantity;
291 if (other->client->pers.inventory[index] > other->client->pers.max_shells)
292 other->client->pers.inventory[index] = other->client->pers.max_shells;
293 }
294
295 item = FindItem("Cells");
296 if (item)
297 {
298 index = ITEM_INDEX(item);
299 other->client->pers.inventory[index] += item->quantity;
300 if (other->client->pers.inventory[index] > other->client->pers.max_cells)
301 other->client->pers.inventory[index] = other->client->pers.max_cells;
302 }
303
304 item = FindItem("Grenades");
305 if (item)
306 {
307 index = ITEM_INDEX(item);
308 other->client->pers.inventory[index] += item->quantity;
309 if (other->client->pers.inventory[index] > other->client->pers.max_grenades)
310 other->client->pers.inventory[index] = other->client->pers.max_grenades;
311 }
312
313 item = FindItem("Rockets");
314 if (item)
315 {
316 index = ITEM_INDEX(item);
317 other->client->pers.inventory[index] += item->quantity;
318 if (other->client->pers.inventory[index] > other->client->pers.max_rockets)
319 other->client->pers.inventory[index] = other->client->pers.max_rockets;
320 }
321
322 item = FindItem("Slugs");
323 if (item)
324 {
325 index = ITEM_INDEX(item);
326 other->client->pers.inventory[index] += item->quantity;
327 if (other->client->pers.inventory[index] > other->client->pers.max_slugs)
328 other->client->pers.inventory[index] = other->client->pers.max_slugs;
329 }
330
331 if (!(ent->spawnflags & DROPPED_ITEM) && (deathmatch->value))
332 SetRespawn (ent, ent->item->quantity);
333
334 return true;
335 }
336
337 //======================================================================
338
Use_Quad(edict_t * ent,gitem_t * item)339 void Use_Quad (edict_t *ent, gitem_t *item)
340 {
341 int timeout;
342
343 ent->client->pers.inventory[ITEM_INDEX(item)]--;
344 ValidateSelectedItem (ent);
345
346 if (quad_drop_timeout_hack)
347 {
348 timeout = quad_drop_timeout_hack;
349 quad_drop_timeout_hack = 0;
350 }
351 else
352 {
353 timeout = 300;
354 }
355
356 if (ent->client->quad_framenum > level.framenum)
357 ent->client->quad_framenum += timeout;
358 else
359 ent->client->quad_framenum = level.framenum + timeout;
360
361 gi.sound(ent, CHAN_ITEM, gi.soundindex("items/damage.wav"), 1, ATTN_NORM, 0);
362 }
363
364 //======================================================================
365
Use_Breather(edict_t * ent,gitem_t * item)366 void Use_Breather (edict_t *ent, gitem_t *item)
367 {
368 ent->client->pers.inventory[ITEM_INDEX(item)]--;
369 ValidateSelectedItem (ent);
370
371 if (ent->client->breather_framenum > level.framenum)
372 ent->client->breather_framenum += 300;
373 else
374 ent->client->breather_framenum = level.framenum + 300;
375
376 // gi.sound(ent, CHAN_ITEM, gi.soundindex("items/damage.wav"), 1, ATTN_NORM, 0);
377 }
378
379 //======================================================================
380
Use_Envirosuit(edict_t * ent,gitem_t * item)381 void Use_Envirosuit (edict_t *ent, gitem_t *item)
382 {
383 ent->client->pers.inventory[ITEM_INDEX(item)]--;
384 ValidateSelectedItem (ent);
385
386 if (ent->client->enviro_framenum > level.framenum)
387 ent->client->enviro_framenum += 300;
388 else
389 ent->client->enviro_framenum = level.framenum + 300;
390
391 // gi.sound(ent, CHAN_ITEM, gi.soundindex("items/damage.wav"), 1, ATTN_NORM, 0);
392 }
393
394 //======================================================================
395
Use_Invulnerability(edict_t * ent,gitem_t * item)396 void Use_Invulnerability (edict_t *ent, gitem_t *item)
397 {
398 ent->client->pers.inventory[ITEM_INDEX(item)]--;
399 ValidateSelectedItem (ent);
400
401 if (ent->client->invincible_framenum > level.framenum)
402 ent->client->invincible_framenum += 300;
403 else
404 ent->client->invincible_framenum = level.framenum + 300;
405
406 gi.sound(ent, CHAN_ITEM, gi.soundindex("items/protect.wav"), 1, ATTN_NORM, 0);
407 }
408
409 //======================================================================
410
Use_Silencer(edict_t * ent,gitem_t * item)411 void Use_Silencer (edict_t *ent, gitem_t *item)
412 {
413 ent->client->pers.inventory[ITEM_INDEX(item)]--;
414 ValidateSelectedItem (ent);
415 ent->client->silencer_shots += 30;
416
417 // gi.sound(ent, CHAN_ITEM, gi.soundindex("items/damage.wav"), 1, ATTN_NORM, 0);
418 }
419
420 //======================================================================
421
Pickup_Key(edict_t * ent,edict_t * other)422 qboolean Pickup_Key (edict_t *ent, edict_t *other)
423 {
424 if (coop->value)
425 {
426 if (strcmp(ent->classname, "key_power_cube") == 0)
427 {
428 if (other->client->pers.power_cubes & ((ent->spawnflags & 0x0000ff00)>> 8))
429 return false;
430 other->client->pers.inventory[ITEM_INDEX(ent->item)]++;
431 other->client->pers.power_cubes |= ((ent->spawnflags & 0x0000ff00) >> 8);
432 }
433 else
434 {
435 if (other->client->pers.inventory[ITEM_INDEX(ent->item)])
436 return false;
437 other->client->pers.inventory[ITEM_INDEX(ent->item)] = 1;
438 }
439 return true;
440 }
441 other->client->pers.inventory[ITEM_INDEX(ent->item)]++;
442 return true;
443 }
444
445 //======================================================================
446
Add_Ammo(edict_t * ent,gitem_t * item,int count)447 qboolean Add_Ammo (edict_t *ent, gitem_t *item, int count)
448 {
449 int index;
450 int max;
451
452 if (!ent->client)
453 return false;
454
455 if (item->tag == AMMO_BULLETS)
456 max = ent->client->pers.max_bullets;
457 else if (item->tag == AMMO_SHELLS)
458 max = ent->client->pers.max_shells;
459 else if (item->tag == AMMO_ROCKETS)
460 max = ent->client->pers.max_rockets;
461 else if (item->tag == AMMO_GRENADES)
462 max = ent->client->pers.max_grenades;
463 else if (item->tag == AMMO_CELLS)
464 max = ent->client->pers.max_cells;
465 else if (item->tag == AMMO_SLUGS)
466 max = ent->client->pers.max_slugs;
467 else
468 return false;
469
470 index = ITEM_INDEX(item);
471
472 if (ent->client->pers.inventory[index] == max)
473 return false;
474
475 ent->client->pers.inventory[index] += count;
476
477 if (ent->client->pers.inventory[index] > max)
478 ent->client->pers.inventory[index] = max;
479
480 return true;
481 }
482
Pickup_Ammo(edict_t * ent,edict_t * other)483 qboolean Pickup_Ammo (edict_t *ent, edict_t *other)
484 {
485 int oldcount;
486 int count;
487 qboolean weapon;
488
489 weapon = (ent->item->flags & IT_WEAPON);
490 if ( (weapon) && ( (int)dmflags->value & DF_INFINITE_AMMO ) )
491 count = 1000;
492 else if (ent->count)
493 count = ent->count;
494 else
495 count = ent->item->quantity;
496
497 oldcount = other->client->pers.inventory[ITEM_INDEX(ent->item)];
498
499 if (!Add_Ammo (other, ent->item, count))
500 return false;
501
502 if (weapon && !oldcount)
503 {
504 if (other->client->pers.weapon != ent->item && ( !deathmatch->value || other->client->pers.weapon == FindItem("blaster") ) )
505 other->client->newweapon = ent->item;
506 }
507
508 if (!(ent->spawnflags & (DROPPED_ITEM | DROPPED_PLAYER_ITEM)) && (deathmatch->value))
509 SetRespawn (ent, 30);
510 return true;
511 }
512
Drop_Ammo(edict_t * ent,gitem_t * item)513 void Drop_Ammo (edict_t *ent, gitem_t *item)
514 {
515 edict_t *dropped;
516 int index;
517
518 index = ITEM_INDEX(item);
519 dropped = Drop_Item (ent, item);
520 if (ent->client->pers.inventory[index] >= item->quantity)
521 dropped->count = item->quantity;
522 else
523 dropped->count = ent->client->pers.inventory[index];
524
525 if (ent->client->pers.weapon &&
526 ent->client->pers.weapon->tag == AMMO_GRENADES &&
527 item->tag == AMMO_GRENADES &&
528 ent->client->pers.inventory[index] - dropped->count <= 0) {
529 gi.cprintf (ent, PRINT_HIGH, "Can't drop current weapon\n");
530 G_FreeEdict(dropped);
531 return;
532 }
533
534 ent->client->pers.inventory[index] -= dropped->count;
535 ValidateSelectedItem (ent);
536 }
537
538
539 //======================================================================
540
MegaHealth_think(edict_t * self)541 void MegaHealth_think (edict_t *self)
542 {
543 if (self->owner->health > self->owner->max_health)
544 {
545 self->nextthink = level.time + 1;
546 self->owner->health -= 1;
547 return;
548 }
549
550 if (!(self->spawnflags & DROPPED_ITEM) && (deathmatch->value))
551 SetRespawn (self, 20);
552 else
553 G_FreeEdict (self);
554 }
555
Pickup_Health(edict_t * ent,edict_t * other)556 qboolean Pickup_Health (edict_t *ent, edict_t *other)
557 {
558 if (!(ent->style & HEALTH_IGNORE_MAX))
559 if (other->health >= other->max_health)
560 return false;
561
562 other->health += ent->count;
563
564 if (!(ent->style & HEALTH_IGNORE_MAX))
565 {
566 if (other->health > other->max_health)
567 other->health = other->max_health;
568 }
569
570 if (ent->style & HEALTH_TIMED)
571 {
572 ent->think = MegaHealth_think;
573 ent->nextthink = level.time + 5;
574 ent->owner = other;
575 ent->flags |= FL_RESPAWN;
576 ent->svflags |= SVF_NOCLIENT;
577 ent->solid = SOLID_NOT;
578 }
579 else
580 {
581 if (!(ent->spawnflags & DROPPED_ITEM) && (deathmatch->value))
582 SetRespawn (ent, 30);
583 }
584
585 return true;
586 }
587
588 //======================================================================
589
ArmorIndex(edict_t * ent)590 int ArmorIndex (edict_t *ent)
591 {
592 if (!ent->client)
593 return 0;
594
595 if (ent->client->pers.inventory[jacket_armor_index] > 0)
596 return jacket_armor_index;
597
598 if (ent->client->pers.inventory[combat_armor_index] > 0)
599 return combat_armor_index;
600
601 if (ent->client->pers.inventory[body_armor_index] > 0)
602 return body_armor_index;
603
604 return 0;
605 }
606
Pickup_Armor(edict_t * ent,edict_t * other)607 qboolean Pickup_Armor (edict_t *ent, edict_t *other)
608 {
609 int old_armor_index;
610 gitem_armor_t *oldinfo;
611 gitem_armor_t *newinfo;
612 int newcount;
613 float salvage;
614 int salvagecount;
615
616 // get info on new armor
617 newinfo = (gitem_armor_t *)ent->item->info;
618
619 old_armor_index = ArmorIndex (other);
620
621 // handle armor shards specially
622 if (ent->item->tag == ARMOR_SHARD)
623 {
624 if (!old_armor_index)
625 other->client->pers.inventory[jacket_armor_index] = 2;
626 else
627 other->client->pers.inventory[old_armor_index] += 2;
628 }
629
630 // if player has no armor, just use it
631 else if (!old_armor_index)
632 {
633 other->client->pers.inventory[ITEM_INDEX(ent->item)] = newinfo->base_count;
634 }
635
636 // use the better armor
637 else
638 {
639 // get info on old armor
640 if (old_armor_index == jacket_armor_index)
641 oldinfo = &jacketarmor_info;
642 else if (old_armor_index == combat_armor_index)
643 oldinfo = &combatarmor_info;
644 else // (old_armor_index == body_armor_index)
645 oldinfo = &bodyarmor_info;
646
647 if (newinfo->normal_protection > oldinfo->normal_protection)
648 {
649 // calc new armor values
650 salvage = oldinfo->normal_protection / newinfo->normal_protection;
651 salvagecount = salvage * other->client->pers.inventory[old_armor_index];
652 newcount = newinfo->base_count + salvagecount;
653 if (newcount > newinfo->max_count)
654 newcount = newinfo->max_count;
655
656 // zero count of old armor so it goes away
657 other->client->pers.inventory[old_armor_index] = 0;
658
659 // change armor to new item with computed value
660 other->client->pers.inventory[ITEM_INDEX(ent->item)] = newcount;
661 }
662 else
663 {
664 // calc new armor values
665 salvage = newinfo->normal_protection / oldinfo->normal_protection;
666 salvagecount = salvage * newinfo->base_count;
667 newcount = other->client->pers.inventory[old_armor_index] + salvagecount;
668 if (newcount > oldinfo->max_count)
669 newcount = oldinfo->max_count;
670
671 // if we're already maxed out then we don't need the new armor
672 if (other->client->pers.inventory[old_armor_index] >= newcount)
673 return false;
674
675 // update current armor value
676 other->client->pers.inventory[old_armor_index] = newcount;
677 }
678 }
679
680 if (!(ent->spawnflags & DROPPED_ITEM) && (deathmatch->value))
681 SetRespawn (ent, 20);
682
683 return true;
684 }
685
686 //======================================================================
687
PowerArmorType(edict_t * ent)688 int PowerArmorType (edict_t *ent)
689 {
690 if (!ent->client)
691 return POWER_ARMOR_NONE;
692
693 if (!(ent->flags & FL_POWER_ARMOR))
694 return POWER_ARMOR_NONE;
695
696 if (ent->client->pers.inventory[power_shield_index] > 0)
697 return POWER_ARMOR_SHIELD;
698
699 if (ent->client->pers.inventory[power_screen_index] > 0)
700 return POWER_ARMOR_SCREEN;
701
702 return POWER_ARMOR_NONE;
703 }
704
Use_PowerArmor(edict_t * ent,gitem_t * item)705 void Use_PowerArmor (edict_t *ent, gitem_t *item)
706 {
707 int index;
708
709 if (ent->flags & FL_POWER_ARMOR)
710 {
711 ent->flags &= ~FL_POWER_ARMOR;
712 gi.sound(ent, CHAN_AUTO, gi.soundindex("misc/power2.wav"), 1, ATTN_NORM, 0);
713 }
714 else
715 {
716 index = ITEM_INDEX(FindItem("cells"));
717 if (!ent->client->pers.inventory[index])
718 {
719 gi.cprintf (ent, PRINT_HIGH, "No cells for power armor.\n");
720 return;
721 }
722 ent->flags |= FL_POWER_ARMOR;
723 gi.sound(ent, CHAN_AUTO, gi.soundindex("misc/power1.wav"), 1, ATTN_NORM, 0);
724 }
725 }
726
Pickup_PowerArmor(edict_t * ent,edict_t * other)727 qboolean Pickup_PowerArmor (edict_t *ent, edict_t *other)
728 {
729 int quantity;
730
731 quantity = other->client->pers.inventory[ITEM_INDEX(ent->item)];
732
733 other->client->pers.inventory[ITEM_INDEX(ent->item)]++;
734
735 if (deathmatch->value)
736 {
737 if (!(ent->spawnflags & DROPPED_ITEM) )
738 SetRespawn (ent, ent->item->quantity);
739 // auto-use for DM only if we didn't already have one
740 if (!quantity)
741 ent->item->use (other, ent->item);
742 }
743
744 return true;
745 }
746
Drop_PowerArmor(edict_t * ent,gitem_t * item)747 void Drop_PowerArmor (edict_t *ent, gitem_t *item)
748 {
749 if ((ent->flags & FL_POWER_ARMOR) && (ent->client->pers.inventory[ITEM_INDEX(item)] == 1))
750 Use_PowerArmor (ent, item);
751 Drop_General (ent, item);
752 }
753
754 //======================================================================
755
756 /*
757 ===============
758 Touch_Item
759 ===============
760 */
Touch_Item(edict_t * ent,edict_t * other,cplane_t * plane,csurface_t * surf)761 void Touch_Item (edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf)
762 {
763 qboolean taken;
764
765 if (!other->client)
766 return;
767 if (other->health < 1)
768 return; // dead people can't pickup
769 if (!ent->item->pickup)
770 return; // not a grabbable item?
771
772 taken = ent->item->pickup(ent, other);
773
774 if (taken)
775 {
776 // flash the screen
777 other->client->bonus_alpha = 0.25;
778
779 // show icon and name on status bar
780 other->client->ps.stats[STAT_PICKUP_ICON] = gi.imageindex(ent->item->icon);
781 other->client->ps.stats[STAT_PICKUP_STRING] = CS_ITEMS+ITEM_INDEX(ent->item);
782 other->client->pickup_msg_time = level.time + 3.0;
783
784 // change selected item
785 if (ent->item->use)
786 other->client->pers.selected_item = other->client->ps.stats[STAT_SELECTED_ITEM] = ITEM_INDEX(ent->item);
787
788 if (ent->item->pickup == Pickup_Health)
789 {
790 if (ent->count == 2)
791 gi.sound(other, CHAN_ITEM, gi.soundindex("items/s_health.wav"), 1, ATTN_NORM, 0);
792 else if (ent->count == 10)
793 gi.sound(other, CHAN_ITEM, gi.soundindex("items/n_health.wav"), 1, ATTN_NORM, 0);
794 else if (ent->count == 25)
795 gi.sound(other, CHAN_ITEM, gi.soundindex("items/l_health.wav"), 1, ATTN_NORM, 0);
796 else // (ent->count == 100)
797 gi.sound(other, CHAN_ITEM, gi.soundindex("items/m_health.wav"), 1, ATTN_NORM, 0);
798 }
799 else if (ent->item->pickup_sound)
800 {
801 gi.sound(other, CHAN_ITEM, gi.soundindex(ent->item->pickup_sound), 1, ATTN_NORM, 0);
802 }
803 }
804
805 if (!(ent->spawnflags & ITEM_TARGETS_USED))
806 {
807 G_UseTargets (ent, other);
808 ent->spawnflags |= ITEM_TARGETS_USED;
809 }
810
811 if (!taken)
812 return;
813
814 if (!((coop->value) && (ent->item->flags & IT_STAY_COOP)) || (ent->spawnflags & (DROPPED_ITEM | DROPPED_PLAYER_ITEM)))
815 {
816 if (ent->flags & FL_RESPAWN)
817 ent->flags &= ~FL_RESPAWN;
818 else
819 G_FreeEdict (ent);
820 }
821 }
822
823 //======================================================================
824
drop_temp_touch(edict_t * ent,edict_t * other,cplane_t * plane,csurface_t * surf)825 static void drop_temp_touch (edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf)
826 {
827 if (other == ent->owner)
828 return;
829
830 Touch_Item (ent, other, plane, surf);
831 }
832
drop_make_touchable(edict_t * ent)833 static void drop_make_touchable (edict_t *ent)
834 {
835 ent->touch = Touch_Item;
836 if (deathmatch->value)
837 {
838 ent->nextthink = level.time + 29;
839 ent->think = G_FreeEdict;
840 }
841 }
842
Drop_Item(edict_t * ent,gitem_t * item)843 edict_t *Drop_Item (edict_t *ent, gitem_t *item)
844 {
845 edict_t *dropped;
846 vec3_t forward, right;
847 vec3_t offset;
848
849 dropped = G_Spawn();
850
851 dropped->classname = item->classname;
852 dropped->item = item;
853 dropped->spawnflags = DROPPED_ITEM;
854 dropped->s.effects = item->world_model_flags;
855 dropped->s.renderfx = RF_GLOW;
856 VectorSet (dropped->mins, -15, -15, -15);
857 VectorSet (dropped->maxs, 15, 15, 15);
858 gi.setmodel (dropped, dropped->item->world_model);
859 dropped->solid = SOLID_TRIGGER;
860 dropped->movetype = MOVETYPE_TOSS;
861 dropped->touch = drop_temp_touch;
862 dropped->owner = ent;
863
864 if (ent->client)
865 {
866 trace_t trace;
867
868 AngleVectors (ent->client->v_angle, forward, right, NULL);
869 VectorSet(offset, 24, 0, -16);
870 G_ProjectSource (ent->s.origin, offset, forward, right, dropped->s.origin);
871 trace = gi.trace (ent->s.origin, dropped->mins, dropped->maxs,
872 dropped->s.origin, ent, CONTENTS_SOLID);
873 VectorCopy (trace.endpos, dropped->s.origin);
874 }
875 else
876 {
877 AngleVectors (ent->s.angles, forward, right, NULL);
878 VectorCopy (ent->s.origin, dropped->s.origin);
879 }
880
881 VectorScale (forward, 100, dropped->velocity);
882 dropped->velocity[2] = 300;
883
884 dropped->think = drop_make_touchable;
885 dropped->nextthink = level.time + 1;
886
887 gi.linkentity (dropped);
888
889 return dropped;
890 }
891
Use_Item(edict_t * ent,edict_t * other,edict_t * activator)892 void Use_Item (edict_t *ent, edict_t *other, edict_t *activator)
893 {
894 ent->svflags &= ~SVF_NOCLIENT;
895 ent->use = NULL;
896
897 if (ent->spawnflags & ITEM_NO_TOUCH)
898 {
899 ent->solid = SOLID_BBOX;
900 ent->touch = NULL;
901 }
902 else
903 {
904 ent->solid = SOLID_TRIGGER;
905 ent->touch = Touch_Item;
906 }
907
908 gi.linkentity (ent);
909 }
910
911 //======================================================================
912
913 /*
914 ================
915 droptofloor
916 ================
917 */
droptofloor(edict_t * ent)918 void droptofloor (edict_t *ent)
919 {
920 trace_t tr;
921 vec3_t dest;
922 float *v;
923
924 v = tv(-15,-15,-15);
925 VectorCopy (v, ent->mins);
926 v = tv(15,15,15);
927 VectorCopy (v, ent->maxs);
928
929 if (ent->model)
930 gi.setmodel (ent, ent->model);
931 else
932 gi.setmodel (ent, ent->item->world_model);
933 ent->solid = SOLID_TRIGGER;
934 ent->movetype = MOVETYPE_TOSS;
935 ent->touch = Touch_Item;
936
937 v = tv(0,0,-128);
938 VectorAdd (ent->s.origin, v, dest);
939
940 tr = gi.trace (ent->s.origin, ent->mins, ent->maxs, dest, ent, MASK_SOLID);
941 if (tr.startsolid)
942 {
943 gi.dprintf ("droptofloor: %s startsolid at %s\n", ent->classname, vtos(ent->s.origin));
944 G_FreeEdict (ent);
945 return;
946 }
947
948 VectorCopy (tr.endpos, ent->s.origin);
949
950 if (ent->team)
951 {
952 ent->flags &= ~FL_TEAMSLAVE;
953 ent->chain = ent->teamchain;
954 ent->teamchain = NULL;
955
956 ent->svflags |= SVF_NOCLIENT;
957 ent->solid = SOLID_NOT;
958 if (ent == ent->teammaster)
959 {
960 ent->nextthink = level.time + FRAMETIME;
961 ent->think = DoRespawn;
962 }
963 }
964
965 if (ent->spawnflags & ITEM_NO_TOUCH)
966 {
967 ent->solid = SOLID_BBOX;
968 ent->touch = NULL;
969 ent->s.effects &= ~EF_ROTATE;
970 ent->s.renderfx &= ~RF_GLOW;
971 }
972
973 if (ent->spawnflags & ITEM_TRIGGER_SPAWN)
974 {
975 ent->svflags |= SVF_NOCLIENT;
976 ent->solid = SOLID_NOT;
977 ent->use = Use_Item;
978 }
979
980 gi.linkentity (ent);
981 }
982
983
984 /*
985 ===============
986 PrecacheItem
987
988 Precaches all data needed for a given item.
989 This will be called for each item spawned in a level,
990 and for each item in each client's inventory.
991 ===============
992 */
PrecacheItem(gitem_t * it)993 void PrecacheItem (gitem_t *it)
994 {
995 char *s, *start;
996 char data[MAX_QPATH];
997 int len;
998 gitem_t *ammo;
999
1000 if (!it)
1001 return;
1002
1003 if (it->pickup_sound)
1004 gi.soundindex (it->pickup_sound);
1005 if (it->world_model)
1006 gi.modelindex (it->world_model);
1007 if (it->view_model)
1008 gi.modelindex (it->view_model);
1009 if (it->icon)
1010 gi.imageindex (it->icon);
1011
1012 // parse everything for its ammo
1013 if (it->ammo && it->ammo[0])
1014 {
1015 ammo = FindItem (it->ammo);
1016 if (ammo != it)
1017 PrecacheItem (ammo);
1018 }
1019
1020 // parse the space seperated precache string for other items
1021 s = it->precaches;
1022 if (!s || !s[0])
1023 return;
1024
1025 while (*s)
1026 {
1027 start = s;
1028 while (*s && *s != ' ')
1029 s++;
1030
1031 len = s-start;
1032 if (len >= MAX_QPATH || len < 5)
1033 gi.error ("PrecacheItem: %s has bad precache string", it->classname);
1034 memcpy (data, start, len);
1035 data[len] = 0;
1036 if (*s)
1037 s++;
1038
1039 // determine type based on extension
1040 if (!strcmp(data+len-3, "md2"))
1041 gi.modelindex (data);
1042 else if (!strcmp(data+len-3, "sp2"))
1043 gi.modelindex (data);
1044 else if (!strcmp(data+len-3, "wav"))
1045 gi.soundindex (data);
1046 if (!strcmp(data+len-3, "pcx"))
1047 gi.imageindex (data);
1048 }
1049 }
1050
1051 /*
1052 ============
1053 SpawnItem
1054
1055 Sets the clipping size and plants the object on the floor.
1056
1057 Items can't be immediately dropped to floor, because they might
1058 be on an entity that hasn't spawned yet.
1059 ============
1060 */
SpawnItem(edict_t * ent,gitem_t * item)1061 void SpawnItem (edict_t *ent, gitem_t *item)
1062 {
1063 PrecacheItem (item);
1064
1065 if (ent->spawnflags)
1066 {
1067 if (strcmp(ent->classname, "key_power_cube") != 0)
1068 {
1069 ent->spawnflags = 0;
1070 gi.dprintf("%s at %s has invalid spawnflags set\n", ent->classname, vtos(ent->s.origin));
1071 }
1072 }
1073
1074 // some items will be prevented in deathmatch
1075 if (deathmatch->value)
1076 {
1077 if ( (int)dmflags->value & DF_NO_ARMOR )
1078 {
1079 if (item->pickup == Pickup_Armor || item->pickup == Pickup_PowerArmor)
1080 {
1081 G_FreeEdict (ent);
1082 return;
1083 }
1084 }
1085 if ( (int)dmflags->value & DF_NO_ITEMS )
1086 {
1087 if (item->pickup == Pickup_Powerup)
1088 {
1089 G_FreeEdict (ent);
1090 return;
1091 }
1092 }
1093 if ( (int)dmflags->value & DF_NO_HEALTH )
1094 {
1095 if (item->pickup == Pickup_Health || item->pickup == Pickup_Adrenaline || item->pickup == Pickup_AncientHead)
1096 {
1097 G_FreeEdict (ent);
1098 return;
1099 }
1100 }
1101 if ( (int)dmflags->value & DF_INFINITE_AMMO )
1102 {
1103 if ( (item->flags == IT_AMMO) || (strcmp(ent->classname, "weapon_bfg") == 0) )
1104 {
1105 G_FreeEdict (ent);
1106 return;
1107 }
1108 }
1109 }
1110
1111 if (coop->value && (strcmp(ent->classname, "key_power_cube") == 0))
1112 {
1113 ent->spawnflags |= (1 << (8 + level.power_cubes));
1114 level.power_cubes++;
1115 }
1116
1117 // don't let them drop items that stay in a coop game
1118 if ((coop->value) && (item->flags & IT_STAY_COOP))
1119 {
1120 item->drop = NULL;
1121 }
1122
1123 ent->item = item;
1124 ent->nextthink = level.time + 2 * FRAMETIME; // items start after other solids
1125 ent->think = droptofloor;
1126 ent->s.effects = item->world_model_flags;
1127 ent->s.renderfx = RF_GLOW;
1128 if (ent->model)
1129 gi.modelindex (ent->model);
1130 }
1131
1132 //======================================================================
1133
1134 gitem_t itemlist[] =
1135 {
1136 {
1137 NULL
1138 }, // leave index 0 alone
1139
1140 //
1141 // ARMOR
1142 //
1143
1144 /*QUAKED item_armor_body (.3 .3 1) (-16 -16 -16) (16 16 16)
1145 */
1146 {
1147 "item_armor_body",
1148 Pickup_Armor,
1149 NULL,
1150 NULL,
1151 NULL,
1152 "misc/ar1_pkup.wav",
1153 "models/items/armor/body/tris.md2", EF_ROTATE,
1154 NULL,
1155 /* icon */ "i_bodyarmor",
1156 /* pickup */ "Body Armor",
1157 /* width */ 3,
1158 0,
1159 NULL,
1160 IT_ARMOR,
1161 0,
1162 &bodyarmor_info,
1163 ARMOR_BODY,
1164 /* precache */ ""
1165 },
1166
1167 /*QUAKED item_armor_combat (.3 .3 1) (-16 -16 -16) (16 16 16)
1168 */
1169 {
1170 "item_armor_combat",
1171 Pickup_Armor,
1172 NULL,
1173 NULL,
1174 NULL,
1175 "misc/ar1_pkup.wav",
1176 "models/items/armor/combat/tris.md2", EF_ROTATE,
1177 NULL,
1178 /* icon */ "i_combatarmor",
1179 /* pickup */ "Combat Armor",
1180 /* width */ 3,
1181 0,
1182 NULL,
1183 IT_ARMOR,
1184 0,
1185 &combatarmor_info,
1186 ARMOR_COMBAT,
1187 /* precache */ ""
1188 },
1189
1190 /*QUAKED item_armor_jacket (.3 .3 1) (-16 -16 -16) (16 16 16)
1191 */
1192 {
1193 "item_armor_jacket",
1194 Pickup_Armor,
1195 NULL,
1196 NULL,
1197 NULL,
1198 "misc/ar1_pkup.wav",
1199 "models/items/armor/jacket/tris.md2", EF_ROTATE,
1200 NULL,
1201 /* icon */ "i_jacketarmor",
1202 /* pickup */ "Jacket Armor",
1203 /* width */ 3,
1204 0,
1205 NULL,
1206 IT_ARMOR,
1207 0,
1208 &jacketarmor_info,
1209 ARMOR_JACKET,
1210 /* precache */ ""
1211 },
1212
1213 /*QUAKED item_armor_shard (.3 .3 1) (-16 -16 -16) (16 16 16)
1214 */
1215 {
1216 "item_armor_shard",
1217 Pickup_Armor,
1218 NULL,
1219 NULL,
1220 NULL,
1221 "misc/ar2_pkup.wav",
1222 "models/items/armor/shard/tris.md2", EF_ROTATE,
1223 NULL,
1224 /* icon */ "i_jacketarmor",
1225 /* pickup */ "Armor Shard",
1226 /* width */ 3,
1227 0,
1228 NULL,
1229 IT_ARMOR,
1230 0,
1231 NULL,
1232 ARMOR_SHARD,
1233 /* precache */ ""
1234 },
1235
1236
1237 /*QUAKED item_power_screen (.3 .3 1) (-16 -16 -16) (16 16 16)
1238 */
1239 {
1240 "item_power_screen",
1241 Pickup_PowerArmor,
1242 Use_PowerArmor,
1243 Drop_PowerArmor,
1244 NULL,
1245 "misc/ar3_pkup.wav",
1246 "models/items/armor/screen/tris.md2", EF_ROTATE,
1247 NULL,
1248 /* icon */ "i_powerscreen",
1249 /* pickup */ "Power Screen",
1250 /* width */ 0,
1251 60,
1252 NULL,
1253 IT_ARMOR,
1254 0,
1255 NULL,
1256 0,
1257 /* precache */ ""
1258 },
1259
1260 /*QUAKED item_power_shield (.3 .3 1) (-16 -16 -16) (16 16 16)
1261 */
1262 {
1263 "item_power_shield",
1264 Pickup_PowerArmor,
1265 Use_PowerArmor,
1266 Drop_PowerArmor,
1267 NULL,
1268 "misc/ar3_pkup.wav",
1269 "models/items/armor/shield/tris.md2", EF_ROTATE,
1270 NULL,
1271 /* icon */ "i_powershield",
1272 /* pickup */ "Power Shield",
1273 /* width */ 0,
1274 60,
1275 NULL,
1276 IT_ARMOR,
1277 0,
1278 NULL,
1279 0,
1280 /* precache */ "misc/power2.wav misc/power1.wav"
1281 },
1282
1283
1284 //
1285 // WEAPONS
1286 //
1287
1288 /* weapon_blaster (.3 .3 1) (-16 -16 -16) (16 16 16)
1289 always owned, never in the world
1290 */
1291 {
1292 "weapon_blaster",
1293 NULL,
1294 Use_Weapon,
1295 NULL,
1296 Weapon_Blaster,
1297 "misc/w_pkup.wav",
1298 NULL, 0,
1299 "models/weapons/v_blast/tris.md2",
1300 /* icon */ "w_blaster",
1301 /* pickup */ "Blaster",
1302 0,
1303 0,
1304 NULL,
1305 IT_WEAPON|IT_STAY_COOP,
1306 WEAP_BLASTER,
1307 NULL,
1308 0,
1309 /* precache */ "weapons/blastf1a.wav misc/lasfly.wav"
1310 },
1311
1312 /*QUAKED weapon_shotgun (.3 .3 1) (-16 -16 -16) (16 16 16)
1313 */
1314 {
1315 "weapon_shotgun",
1316 Pickup_Weapon,
1317 Use_Weapon,
1318 Drop_Weapon,
1319 Weapon_Shotgun,
1320 "misc/w_pkup.wav",
1321 "models/weapons/g_shotg/tris.md2", EF_ROTATE,
1322 "models/weapons/v_shotg/tris.md2",
1323 /* icon */ "w_shotgun",
1324 /* pickup */ "Shotgun",
1325 0,
1326 1,
1327 "Shells",
1328 IT_WEAPON|IT_STAY_COOP,
1329 WEAP_SHOTGUN,
1330 NULL,
1331 0,
1332 /* precache */ "weapons/shotgf1b.wav weapons/shotgr1b.wav"
1333 },
1334
1335 /*QUAKED weapon_supershotgun (.3 .3 1) (-16 -16 -16) (16 16 16)
1336 */
1337 {
1338 "weapon_supershotgun",
1339 Pickup_Weapon,
1340 Use_Weapon,
1341 Drop_Weapon,
1342 Weapon_SuperShotgun,
1343 "misc/w_pkup.wav",
1344 "models/weapons/g_shotg2/tris.md2", EF_ROTATE,
1345 "models/weapons/v_shotg2/tris.md2",
1346 /* icon */ "w_sshotgun",
1347 /* pickup */ "Super Shotgun",
1348 0,
1349 2,
1350 "Shells",
1351 IT_WEAPON|IT_STAY_COOP,
1352 WEAP_SUPERSHOTGUN,
1353 NULL,
1354 0,
1355 /* precache */ "weapons/sshotf1b.wav"
1356 },
1357
1358 /*QUAKED weapon_machinegun (.3 .3 1) (-16 -16 -16) (16 16 16)
1359 */
1360 {
1361 "weapon_machinegun",
1362 Pickup_Weapon,
1363 Use_Weapon,
1364 Drop_Weapon,
1365 Weapon_Machinegun,
1366 "misc/w_pkup.wav",
1367 "models/weapons/g_machn/tris.md2", EF_ROTATE,
1368 "models/weapons/v_machn/tris.md2",
1369 /* icon */ "w_machinegun",
1370 /* pickup */ "Machinegun",
1371 0,
1372 1,
1373 "Bullets",
1374 IT_WEAPON|IT_STAY_COOP,
1375 WEAP_MACHINEGUN,
1376 NULL,
1377 0,
1378 /* precache */ "weapons/machgf1b.wav weapons/machgf2b.wav weapons/machgf3b.wav weapons/machgf4b.wav weapons/machgf5b.wav"
1379 },
1380
1381 /*QUAKED weapon_chaingun (.3 .3 1) (-16 -16 -16) (16 16 16)
1382 */
1383 {
1384 "weapon_chaingun",
1385 Pickup_Weapon,
1386 Use_Weapon,
1387 Drop_Weapon,
1388 Weapon_Chaingun,
1389 "misc/w_pkup.wav",
1390 "models/weapons/g_chain/tris.md2", EF_ROTATE,
1391 "models/weapons/v_chain/tris.md2",
1392 /* icon */ "w_chaingun",
1393 /* pickup */ "Chaingun",
1394 0,
1395 1,
1396 "Bullets",
1397 IT_WEAPON|IT_STAY_COOP,
1398 WEAP_CHAINGUN,
1399 NULL,
1400 0,
1401 /* precache */ "weapons/chngnu1a.wav weapons/chngnl1a.wav weapons/machgf3b.wav` weapons/chngnd1a.wav"
1402 },
1403
1404 /*QUAKED ammo_grenades (.3 .3 1) (-16 -16 -16) (16 16 16)
1405 */
1406 {
1407 "ammo_grenades",
1408 Pickup_Ammo,
1409 Use_Weapon,
1410 Drop_Ammo,
1411 Weapon_Grenade,
1412 "misc/am_pkup.wav",
1413 "models/items/ammo/grenades/medium/tris.md2", 0,
1414 "models/weapons/v_handgr/tris.md2",
1415 /* icon */ "a_grenades",
1416 /* pickup */ "Grenades",
1417 /* width */ 3,
1418 5,
1419 "grenades",
1420 IT_AMMO|IT_WEAPON,
1421 WEAP_GRENADES,
1422 NULL,
1423 AMMO_GRENADES,
1424 /* precache */ "weapons/hgrent1a.wav weapons/hgrena1b.wav weapons/hgrenc1b.wav weapons/hgrenb1a.wav weapons/hgrenb2a.wav "
1425 },
1426
1427 /*QUAKED weapon_grenadelauncher (.3 .3 1) (-16 -16 -16) (16 16 16)
1428 */
1429 {
1430 "weapon_grenadelauncher",
1431 Pickup_Weapon,
1432 Use_Weapon,
1433 Drop_Weapon,
1434 Weapon_GrenadeLauncher,
1435 "misc/w_pkup.wav",
1436 "models/weapons/g_launch/tris.md2", EF_ROTATE,
1437 "models/weapons/v_launch/tris.md2",
1438 /* icon */ "w_glauncher",
1439 /* pickup */ "Grenade Launcher",
1440 0,
1441 1,
1442 "Grenades",
1443 IT_WEAPON|IT_STAY_COOP,
1444 WEAP_GRENADELAUNCHER,
1445 NULL,
1446 0,
1447 /* precache */ "models/objects/grenade/tris.md2 weapons/grenlf1a.wav weapons/grenlr1b.wav weapons/grenlb1b.wav"
1448 },
1449
1450 /*QUAKED weapon_rocketlauncher (.3 .3 1) (-16 -16 -16) (16 16 16)
1451 */
1452 {
1453 "weapon_rocketlauncher",
1454 Pickup_Weapon,
1455 Use_Weapon,
1456 Drop_Weapon,
1457 Weapon_RocketLauncher,
1458 "misc/w_pkup.wav",
1459 "models/weapons/g_rocket/tris.md2", EF_ROTATE,
1460 "models/weapons/v_rocket/tris.md2",
1461 /* icon */ "w_rlauncher",
1462 /* pickup */ "Rocket Launcher",
1463 0,
1464 1,
1465 "Rockets",
1466 IT_WEAPON|IT_STAY_COOP,
1467 WEAP_ROCKETLAUNCHER,
1468 NULL,
1469 0,
1470 /* precache */ "models/objects/rocket/tris.md2 weapons/rockfly.wav weapons/rocklf1a.wav weapons/rocklr1b.wav models/objects/debris2/tris.md2"
1471 },
1472
1473 /*QUAKED weapon_hyperblaster (.3 .3 1) (-16 -16 -16) (16 16 16)
1474 */
1475 {
1476 "weapon_hyperblaster",
1477 Pickup_Weapon,
1478 Use_Weapon,
1479 Drop_Weapon,
1480 Weapon_HyperBlaster,
1481 "misc/w_pkup.wav",
1482 "models/weapons/g_hyperb/tris.md2", EF_ROTATE,
1483 "models/weapons/v_hyperb/tris.md2",
1484 /* icon */ "w_hyperblaster",
1485 /* pickup */ "HyperBlaster",
1486 0,
1487 1,
1488 "Cells",
1489 IT_WEAPON|IT_STAY_COOP,
1490 WEAP_HYPERBLASTER,
1491 NULL,
1492 0,
1493 /* precache */ "weapons/hyprbu1a.wav weapons/hyprbl1a.wav weapons/hyprbf1a.wav weapons/hyprbd1a.wav misc/lasfly.wav"
1494 },
1495
1496 /*QUAKED weapon_railgun (.3 .3 1) (-16 -16 -16) (16 16 16)
1497 */
1498 {
1499 "weapon_railgun",
1500 Pickup_Weapon,
1501 Use_Weapon,
1502 Drop_Weapon,
1503 Weapon_Railgun,
1504 "misc/w_pkup.wav",
1505 "models/weapons/g_rail/tris.md2", EF_ROTATE,
1506 "models/weapons/v_rail/tris.md2",
1507 /* icon */ "w_railgun",
1508 /* pickup */ "Railgun",
1509 0,
1510 1,
1511 "Slugs",
1512 IT_WEAPON|IT_STAY_COOP,
1513 WEAP_RAILGUN,
1514 NULL,
1515 0,
1516 /* precache */ "weapons/rg_hum.wav"
1517 },
1518
1519 /*QUAKED weapon_bfg (.3 .3 1) (-16 -16 -16) (16 16 16)
1520 */
1521 {
1522 "weapon_bfg",
1523 Pickup_Weapon,
1524 Use_Weapon,
1525 Drop_Weapon,
1526 Weapon_BFG,
1527 "misc/w_pkup.wav",
1528 "models/weapons/g_bfg/tris.md2", EF_ROTATE,
1529 "models/weapons/v_bfg/tris.md2",
1530 /* icon */ "w_bfg",
1531 /* pickup */ "BFG10K",
1532 0,
1533 50,
1534 "Cells",
1535 IT_WEAPON|IT_STAY_COOP,
1536 WEAP_BFG,
1537 NULL,
1538 0,
1539 /* precache */ "sprites/s_bfg1.sp2 sprites/s_bfg2.sp2 sprites/s_bfg3.sp2 weapons/bfg__f1y.wav weapons/bfg__l1a.wav weapons/bfg__x1b.wav weapons/bfg_hum.wav"
1540 },
1541
1542 //
1543 // AMMO ITEMS
1544 //
1545
1546 /*QUAKED ammo_shells (.3 .3 1) (-16 -16 -16) (16 16 16)
1547 */
1548 {
1549 "ammo_shells",
1550 Pickup_Ammo,
1551 NULL,
1552 Drop_Ammo,
1553 NULL,
1554 "misc/am_pkup.wav",
1555 "models/items/ammo/shells/medium/tris.md2", 0,
1556 NULL,
1557 /* icon */ "a_shells",
1558 /* pickup */ "Shells",
1559 /* width */ 3,
1560 10,
1561 NULL,
1562 IT_AMMO,
1563 0,
1564 NULL,
1565 AMMO_SHELLS,
1566 /* precache */ ""
1567 },
1568
1569 /*QUAKED ammo_bullets (.3 .3 1) (-16 -16 -16) (16 16 16)
1570 */
1571 {
1572 "ammo_bullets",
1573 Pickup_Ammo,
1574 NULL,
1575 Drop_Ammo,
1576 NULL,
1577 "misc/am_pkup.wav",
1578 "models/items/ammo/bullets/medium/tris.md2", 0,
1579 NULL,
1580 /* icon */ "a_bullets",
1581 /* pickup */ "Bullets",
1582 /* width */ 3,
1583 50,
1584 NULL,
1585 IT_AMMO,
1586 0,
1587 NULL,
1588 AMMO_BULLETS,
1589 /* precache */ ""
1590 },
1591
1592 /*QUAKED ammo_cells (.3 .3 1) (-16 -16 -16) (16 16 16)
1593 */
1594 {
1595 "ammo_cells",
1596 Pickup_Ammo,
1597 NULL,
1598 Drop_Ammo,
1599 NULL,
1600 "misc/am_pkup.wav",
1601 "models/items/ammo/cells/medium/tris.md2", 0,
1602 NULL,
1603 /* icon */ "a_cells",
1604 /* pickup */ "Cells",
1605 /* width */ 3,
1606 50,
1607 NULL,
1608 IT_AMMO,
1609 0,
1610 NULL,
1611 AMMO_CELLS,
1612 /* precache */ ""
1613 },
1614
1615 /*QUAKED ammo_rockets (.3 .3 1) (-16 -16 -16) (16 16 16)
1616 */
1617 {
1618 "ammo_rockets",
1619 Pickup_Ammo,
1620 NULL,
1621 Drop_Ammo,
1622 NULL,
1623 "misc/am_pkup.wav",
1624 "models/items/ammo/rockets/medium/tris.md2", 0,
1625 NULL,
1626 /* icon */ "a_rockets",
1627 /* pickup */ "Rockets",
1628 /* width */ 3,
1629 5,
1630 NULL,
1631 IT_AMMO,
1632 0,
1633 NULL,
1634 AMMO_ROCKETS,
1635 /* precache */ ""
1636 },
1637
1638 /*QUAKED ammo_slugs (.3 .3 1) (-16 -16 -16) (16 16 16)
1639 */
1640 {
1641 "ammo_slugs",
1642 Pickup_Ammo,
1643 NULL,
1644 Drop_Ammo,
1645 NULL,
1646 "misc/am_pkup.wav",
1647 "models/items/ammo/slugs/medium/tris.md2", 0,
1648 NULL,
1649 /* icon */ "a_slugs",
1650 /* pickup */ "Slugs",
1651 /* width */ 3,
1652 10,
1653 NULL,
1654 IT_AMMO,
1655 0,
1656 NULL,
1657 AMMO_SLUGS,
1658 /* precache */ ""
1659 },
1660
1661
1662 //
1663 // POWERUP ITEMS
1664 //
1665 /*QUAKED item_quad (.3 .3 1) (-16 -16 -16) (16 16 16)
1666 */
1667 {
1668 "item_quad",
1669 Pickup_Powerup,
1670 Use_Quad,
1671 Drop_General,
1672 NULL,
1673 "items/pkup.wav",
1674 "models/items/quaddama/tris.md2", EF_ROTATE,
1675 NULL,
1676 /* icon */ "p_quad",
1677 /* pickup */ "Quad Damage",
1678 /* width */ 2,
1679 60,
1680 NULL,
1681 IT_POWERUP,
1682 0,
1683 NULL,
1684 0,
1685 /* precache */ "items/damage.wav items/damage2.wav items/damage3.wav"
1686 },
1687
1688 /*QUAKED item_invulnerability (.3 .3 1) (-16 -16 -16) (16 16 16)
1689 */
1690 {
1691 "item_invulnerability",
1692 Pickup_Powerup,
1693 Use_Invulnerability,
1694 Drop_General,
1695 NULL,
1696 "items/pkup.wav",
1697 "models/items/invulner/tris.md2", EF_ROTATE,
1698 NULL,
1699 /* icon */ "p_invulnerability",
1700 /* pickup */ "Invulnerability",
1701 /* width */ 2,
1702 300,
1703 NULL,
1704 IT_POWERUP,
1705 0,
1706 NULL,
1707 0,
1708 /* precache */ "items/protect.wav items/protect2.wav items/protect4.wav"
1709 },
1710
1711 /*QUAKED item_silencer (.3 .3 1) (-16 -16 -16) (16 16 16)
1712 */
1713 {
1714 "item_silencer",
1715 Pickup_Powerup,
1716 Use_Silencer,
1717 Drop_General,
1718 NULL,
1719 "items/pkup.wav",
1720 "models/items/silencer/tris.md2", EF_ROTATE,
1721 NULL,
1722 /* icon */ "p_silencer",
1723 /* pickup */ "Silencer",
1724 /* width */ 2,
1725 60,
1726 NULL,
1727 IT_POWERUP,
1728 0,
1729 NULL,
1730 0,
1731 /* precache */ ""
1732 },
1733
1734 /*QUAKED item_breather (.3 .3 1) (-16 -16 -16) (16 16 16)
1735 */
1736 {
1737 "item_breather",
1738 Pickup_Powerup,
1739 Use_Breather,
1740 Drop_General,
1741 NULL,
1742 "items/pkup.wav",
1743 "models/items/breather/tris.md2", EF_ROTATE,
1744 NULL,
1745 /* icon */ "p_rebreather",
1746 /* pickup */ "Rebreather",
1747 /* width */ 2,
1748 60,
1749 NULL,
1750 IT_STAY_COOP|IT_POWERUP,
1751 0,
1752 NULL,
1753 0,
1754 /* precache */ "items/airout.wav"
1755 },
1756
1757 /*QUAKED item_enviro (.3 .3 1) (-16 -16 -16) (16 16 16)
1758 */
1759 {
1760 "item_enviro",
1761 Pickup_Powerup,
1762 Use_Envirosuit,
1763 Drop_General,
1764 NULL,
1765 "items/pkup.wav",
1766 "models/items/enviro/tris.md2", EF_ROTATE,
1767 NULL,
1768 /* icon */ "p_envirosuit",
1769 /* pickup */ "Environment Suit",
1770 /* width */ 2,
1771 60,
1772 NULL,
1773 IT_STAY_COOP|IT_POWERUP,
1774 0,
1775 NULL,
1776 0,
1777 /* precache */ "items/airout.wav"
1778 },
1779
1780 /*QUAKED item_ancient_head (.3 .3 1) (-16 -16 -16) (16 16 16)
1781 Special item that gives +2 to maximum health
1782 */
1783 {
1784 "item_ancient_head",
1785 Pickup_AncientHead,
1786 NULL,
1787 NULL,
1788 NULL,
1789 "items/pkup.wav",
1790 "models/items/c_head/tris.md2", EF_ROTATE,
1791 NULL,
1792 /* icon */ "i_fixme",
1793 /* pickup */ "Ancient Head",
1794 /* width */ 2,
1795 60,
1796 NULL,
1797 0,
1798 0,
1799 NULL,
1800 0,
1801 /* precache */ ""
1802 },
1803
1804 /*QUAKED item_adrenaline (.3 .3 1) (-16 -16 -16) (16 16 16)
1805 gives +1 to maximum health
1806 */
1807 {
1808 "item_adrenaline",
1809 Pickup_Adrenaline,
1810 NULL,
1811 NULL,
1812 NULL,
1813 "items/pkup.wav",
1814 "models/items/adrenal/tris.md2", EF_ROTATE,
1815 NULL,
1816 /* icon */ "p_adrenaline",
1817 /* pickup */ "Adrenaline",
1818 /* width */ 2,
1819 60,
1820 NULL,
1821 0,
1822 0,
1823 NULL,
1824 0,
1825 /* precache */ ""
1826 },
1827
1828 /*QUAKED item_bandolier (.3 .3 1) (-16 -16 -16) (16 16 16)
1829 */
1830 {
1831 "item_bandolier",
1832 Pickup_Bandolier,
1833 NULL,
1834 NULL,
1835 NULL,
1836 "items/pkup.wav",
1837 "models/items/band/tris.md2", EF_ROTATE,
1838 NULL,
1839 /* icon */ "p_bandolier",
1840 /* pickup */ "Bandolier",
1841 /* width */ 2,
1842 60,
1843 NULL,
1844 0,
1845 0,
1846 NULL,
1847 0,
1848 /* precache */ ""
1849 },
1850
1851 /*QUAKED item_pack (.3 .3 1) (-16 -16 -16) (16 16 16)
1852 */
1853 {
1854 "item_pack",
1855 Pickup_Pack,
1856 NULL,
1857 NULL,
1858 NULL,
1859 "items/pkup.wav",
1860 "models/items/pack/tris.md2", EF_ROTATE,
1861 NULL,
1862 /* icon */ "i_pack",
1863 /* pickup */ "Ammo Pack",
1864 /* width */ 2,
1865 180,
1866 NULL,
1867 0,
1868 0,
1869 NULL,
1870 0,
1871 /* precache */ ""
1872 },
1873
1874 //
1875 // KEYS
1876 //
1877 /*QUAKED key_data_cd (0 .5 .8) (-16 -16 -16) (16 16 16)
1878 key for computer centers
1879 */
1880 {
1881 "key_data_cd",
1882 Pickup_Key,
1883 NULL,
1884 Drop_General,
1885 NULL,
1886 "items/pkup.wav",
1887 "models/items/keys/data_cd/tris.md2", EF_ROTATE,
1888 NULL,
1889 "k_datacd",
1890 "Data CD",
1891 2,
1892 0,
1893 NULL,
1894 IT_STAY_COOP|IT_KEY,
1895 0,
1896 NULL,
1897 0,
1898 /* precache */ ""
1899 },
1900
1901 /*QUAKED key_power_cube (0 .5 .8) (-16 -16 -16) (16 16 16) TRIGGER_SPAWN NO_TOUCH
1902 warehouse circuits
1903 */
1904 {
1905 "key_power_cube",
1906 Pickup_Key,
1907 NULL,
1908 Drop_General,
1909 NULL,
1910 "items/pkup.wav",
1911 "models/items/keys/power/tris.md2", EF_ROTATE,
1912 NULL,
1913 "k_powercube",
1914 "Power Cube",
1915 2,
1916 0,
1917 NULL,
1918 IT_STAY_COOP|IT_KEY,
1919 0,
1920 NULL,
1921 0,
1922 /* precache */ ""
1923 },
1924
1925 /*QUAKED key_pyramid (0 .5 .8) (-16 -16 -16) (16 16 16)
1926 key for the entrance of jail3
1927 */
1928 {
1929 "key_pyramid",
1930 Pickup_Key,
1931 NULL,
1932 Drop_General,
1933 NULL,
1934 "items/pkup.wav",
1935 "models/items/keys/pyramid/tris.md2", EF_ROTATE,
1936 NULL,
1937 "k_pyramid",
1938 "Pyramid Key",
1939 2,
1940 0,
1941 NULL,
1942 IT_STAY_COOP|IT_KEY,
1943 0,
1944 NULL,
1945 0,
1946 /* precache */ ""
1947 },
1948
1949 /*QUAKED key_data_spinner (0 .5 .8) (-16 -16 -16) (16 16 16)
1950 key for the city computer
1951 */
1952 {
1953 "key_data_spinner",
1954 Pickup_Key,
1955 NULL,
1956 Drop_General,
1957 NULL,
1958 "items/pkup.wav",
1959 "models/items/keys/spinner/tris.md2", EF_ROTATE,
1960 NULL,
1961 "k_dataspin",
1962 "Data Spinner",
1963 2,
1964 0,
1965 NULL,
1966 IT_STAY_COOP|IT_KEY,
1967 0,
1968 NULL,
1969 0,
1970 /* precache */ ""
1971 },
1972
1973 /*QUAKED key_pass (0 .5 .8) (-16 -16 -16) (16 16 16)
1974 security pass for the security level
1975 */
1976 {
1977 "key_pass",
1978 Pickup_Key,
1979 NULL,
1980 Drop_General,
1981 NULL,
1982 "items/pkup.wav",
1983 "models/items/keys/pass/tris.md2", EF_ROTATE,
1984 NULL,
1985 "k_security",
1986 "Security Pass",
1987 2,
1988 0,
1989 NULL,
1990 IT_STAY_COOP|IT_KEY,
1991 0,
1992 NULL,
1993 0,
1994 /* precache */ ""
1995 },
1996
1997 /*QUAKED key_blue_key (0 .5 .8) (-16 -16 -16) (16 16 16)
1998 normal door key - blue
1999 */
2000 {
2001 "key_blue_key",
2002 Pickup_Key,
2003 NULL,
2004 Drop_General,
2005 NULL,
2006 "items/pkup.wav",
2007 "models/items/keys/key/tris.md2", EF_ROTATE,
2008 NULL,
2009 "k_bluekey",
2010 "Blue Key",
2011 2,
2012 0,
2013 NULL,
2014 IT_STAY_COOP|IT_KEY,
2015 0,
2016 NULL,
2017 0,
2018 /* precache */ ""
2019 },
2020
2021 /*QUAKED key_red_key (0 .5 .8) (-16 -16 -16) (16 16 16)
2022 normal door key - red
2023 */
2024 {
2025 "key_red_key",
2026 Pickup_Key,
2027 NULL,
2028 Drop_General,
2029 NULL,
2030 "items/pkup.wav",
2031 "models/items/keys/red_key/tris.md2", EF_ROTATE,
2032 NULL,
2033 "k_redkey",
2034 "Red Key",
2035 2,
2036 0,
2037 NULL,
2038 IT_STAY_COOP|IT_KEY,
2039 0,
2040 NULL,
2041 0,
2042 /* precache */ ""
2043 },
2044
2045 /*QUAKED key_commander_head (0 .5 .8) (-16 -16 -16) (16 16 16)
2046 tank commander's head
2047 */
2048 {
2049 "key_commander_head",
2050 Pickup_Key,
2051 NULL,
2052 Drop_General,
2053 NULL,
2054 "items/pkup.wav",
2055 "models/monsters/commandr/head/tris.md2", EF_GIB,
2056 NULL,
2057 /* icon */ "k_comhead",
2058 /* pickup */ "Commander's Head",
2059 /* width */ 2,
2060 0,
2061 NULL,
2062 IT_STAY_COOP|IT_KEY,
2063 0,
2064 NULL,
2065 0,
2066 /* precache */ ""
2067 },
2068
2069 /*QUAKED key_airstrike_target (0 .5 .8) (-16 -16 -16) (16 16 16)
2070 tank commander's head
2071 */
2072 {
2073 "key_airstrike_target",
2074 Pickup_Key,
2075 NULL,
2076 Drop_General,
2077 NULL,
2078 "items/pkup.wav",
2079 "models/items/keys/target/tris.md2", EF_ROTATE,
2080 NULL,
2081 /* icon */ "i_airstrike",
2082 /* pickup */ "Airstrike Marker",
2083 /* width */ 2,
2084 0,
2085 NULL,
2086 IT_STAY_COOP|IT_KEY,
2087 0,
2088 NULL,
2089 0,
2090 /* precache */ ""
2091 },
2092
2093 {
2094 NULL,
2095 Pickup_Health,
2096 NULL,
2097 NULL,
2098 NULL,
2099 "items/pkup.wav",
2100 NULL, 0,
2101 NULL,
2102 /* icon */ "i_health",
2103 /* pickup */ "Health",
2104 /* width */ 3,
2105 0,
2106 NULL,
2107 0,
2108 0,
2109 NULL,
2110 0,
2111 /* precache */ "items/s_health.wav items/n_health.wav items/l_health.wav items/m_health.wav"
2112 },
2113
2114 // end of list marker
2115 {NULL}
2116 };
2117
2118
2119 /*QUAKED item_health (.3 .3 1) (-16 -16 -16) (16 16 16)
2120 */
SP_item_health(edict_t * self)2121 void SP_item_health (edict_t *self)
2122 {
2123 if ( deathmatch->value && ((int)dmflags->value & DF_NO_HEALTH) )
2124 {
2125 G_FreeEdict (self);
2126 return;
2127 }
2128
2129 self->model = "models/items/healing/medium/tris.md2";
2130 self->count = 10;
2131 SpawnItem (self, FindItem ("Health"));
2132 gi.soundindex ("items/n_health.wav");
2133 }
2134
2135 /*QUAKED item_health_small (.3 .3 1) (-16 -16 -16) (16 16 16)
2136 */
SP_item_health_small(edict_t * self)2137 void SP_item_health_small (edict_t *self)
2138 {
2139 if ( deathmatch->value && ((int)dmflags->value & DF_NO_HEALTH) )
2140 {
2141 G_FreeEdict (self);
2142 return;
2143 }
2144
2145 self->model = "models/items/healing/stimpack/tris.md2";
2146 self->count = 2;
2147 SpawnItem (self, FindItem ("Health"));
2148 self->style = HEALTH_IGNORE_MAX;
2149 gi.soundindex ("items/s_health.wav");
2150 }
2151
2152 /*QUAKED item_health_large (.3 .3 1) (-16 -16 -16) (16 16 16)
2153 */
SP_item_health_large(edict_t * self)2154 void SP_item_health_large (edict_t *self)
2155 {
2156 if ( deathmatch->value && ((int)dmflags->value & DF_NO_HEALTH) )
2157 {
2158 G_FreeEdict (self);
2159 return;
2160 }
2161
2162 self->model = "models/items/healing/large/tris.md2";
2163 self->count = 25;
2164 SpawnItem (self, FindItem ("Health"));
2165 gi.soundindex ("items/l_health.wav");
2166 }
2167
2168 /*QUAKED item_health_mega (.3 .3 1) (-16 -16 -16) (16 16 16)
2169 */
SP_item_health_mega(edict_t * self)2170 void SP_item_health_mega (edict_t *self)
2171 {
2172 if ( deathmatch->value && ((int)dmflags->value & DF_NO_HEALTH) )
2173 {
2174 G_FreeEdict (self);
2175 return;
2176 }
2177
2178 self->model = "models/items/mega_h/tris.md2";
2179 self->count = 100;
2180 SpawnItem (self, FindItem ("Health"));
2181 gi.soundindex ("items/m_health.wav");
2182 self->style = HEALTH_IGNORE_MAX|HEALTH_TIMED;
2183 }
2184
2185
InitItems(void)2186 void InitItems (void)
2187 {
2188 game.num_items = sizeof(itemlist)/sizeof(itemlist[0]) - 1;
2189 }
2190
2191
2192
2193 /*
2194 ===============
2195 SetItemNames
2196
2197 Called by worldspawn
2198 ===============
2199 */
SetItemNames(void)2200 void SetItemNames (void)
2201 {
2202 int i;
2203 gitem_t *it;
2204
2205 for (i=0 ; i<game.num_items ; i++)
2206 {
2207 it = &itemlist[i];
2208 gi.configstring (CS_ITEMS+i, it->pickup_name);
2209 }
2210
2211 jacket_armor_index = ITEM_INDEX(FindItem("Jacket Armor"));
2212 combat_armor_index = ITEM_INDEX(FindItem("Combat Armor"));
2213 body_armor_index = ITEM_INDEX(FindItem("Body Armor"));
2214 power_screen_index = ITEM_INDEX(FindItem("Power Screen"));
2215 power_shield_index = ITEM_INDEX(FindItem("Power Shield"));
2216 }
2217