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