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