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