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