1 /* $Id: weapon.c,v 1.6 2002/08/06 05:21:33 btb Exp $ */
2 /*
3 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
4 SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
5 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
6 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
7 IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
8 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
9 FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
10 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
11 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
12 COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
13 */
14 
15 #ifdef HAVE_CONFIG_H
16 #include <conf.h>
17 #endif
18 
19 #ifdef RCS
20 static char rcsid[] = "$Id: weapon.c,v 1.6 2002/08/06 05:21:33 btb Exp $";
21 #endif
22 
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <string.h>
26 
27 #include "game.h"
28 #include "laser.h"
29 #include "weapon.h"
30 #include "mono.h"
31 #include "player.h"
32 #include "gauges.h"
33 #include "error.h"
34 #include "sounds.h"
35 #include "text.h"
36 #include "powerup.h"
37 #include "fireball.h"
38 #include "newdemo.h"
39 #include "multi.h"
40 #include "newmenu.h"
41 #include "ai.h"
42 #include "args.h"
43 
44 #if defined (TACTILE)
45 #include "tactile.h"
46 #endif
47 
48 int POrderList (int num);
49 int SOrderList (int num);
50 //	Note, only Vulcan cannon requires ammo.
51 // NOTE: Now Vulcan and Gauss require ammo. -5/3/95 Yuan
52 //ubyte	Default_primary_ammo_level[MAX_PRIMARY_WEAPONS] = {255, 0, 255, 255, 255};
53 //ubyte	Default_secondary_ammo_level[MAX_SECONDARY_WEAPONS] = {3, 0, 0, 0, 0};
54 
55 //	Convert primary weapons to indices in Weapon_info array.
56 ubyte Primary_weapon_to_weapon_info[MAX_PRIMARY_WEAPONS] = {LASER_ID, VULCAN_ID, SPREADFIRE_ID, PLASMA_ID, FUSION_ID, SUPER_LASER_ID, GAUSS_ID, HELIX_ID, PHOENIX_ID, OMEGA_ID};
57 ubyte Secondary_weapon_to_weapon_info[MAX_SECONDARY_WEAPONS] = {CONCUSSION_ID, HOMING_ID, PROXIMITY_ID, SMART_ID, MEGA_ID, FLASH_ID, GUIDEDMISS_ID, SUPERPROX_ID, MERCURY_ID, EARTHSHAKER_ID};
58 
59 //for each Secondary weapon, which gun it fires out of
60 ubyte Secondary_weapon_to_gun_num[MAX_SECONDARY_WEAPONS] = {4,4,7,7,7,4,4,7,4,7};
61 
62 int Primary_ammo_max[MAX_PRIMARY_WEAPONS] = {0, VULCAN_AMMO_MAX, 0, 0, 0, 0, VULCAN_AMMO_MAX, 0, 0, 0};
63 ubyte Secondary_ammo_max[MAX_SECONDARY_WEAPONS] = {20, 10, 10, 5, 5, 20, 20, 15, 10, 10};
64 
65 //for each primary weapon, what kind of powerup gives weapon
66 ubyte Primary_weapon_to_powerup[MAX_PRIMARY_WEAPONS] = {POW_LASER,POW_VULCAN_WEAPON,POW_SPREADFIRE_WEAPON,POW_PLASMA_WEAPON,POW_FUSION_WEAPON,POW_LASER,POW_GAUSS_WEAPON,POW_HELIX_WEAPON,POW_PHOENIX_WEAPON,POW_OMEGA_WEAPON};
67 
68 //for each Secondary weapon, what kind of powerup gives weapon
69 ubyte Secondary_weapon_to_powerup[MAX_SECONDARY_WEAPONS] = {POW_MISSILE_1,POW_HOMING_AMMO_1,POW_PROXIMITY_WEAPON,POW_SMARTBOMB_WEAPON,POW_MEGA_WEAPON,POW_SMISSILE1_1,POW_GUIDED_MISSILE_1,POW_SMART_MINE,POW_MERCURY_MISSILE_1,POW_EARTHSHAKER_MISSILE};
70 
71 weapon_info Weapon_info[MAX_WEAPON_TYPES];
72 int	N_weapon_types=0;
73 byte	Primary_weapon, Secondary_weapon;
74 
75 // autoselect ordering
76 
77 ubyte PrimaryOrder[]={9,8,7,6,5,4,3,2,1,0,255};
78 ubyte SecondaryOrder[]={9,8,4,3,1,5,0,255,7,6,2};
79 
80 ubyte DefaultPrimaryOrder[]={9,8,7,6,5,4,3,2,1,0,255};
81 ubyte DefaultSecondaryOrder[]={9,8,4,3,1,5,0,255,7,6,2};
82 
83 // Cycling weapon key pressed?
84 
85 ubyte Cycling=0;
86 
87 //allow player to reorder menus?
88 extern ubyte MenuReordering;
89 
90 //char	*Primary_weapon_names[MAX_PRIMARY_WEAPONS] = {
91 //	"Laser Cannon",
92 //	"Vulcan Cannon",
93 //	"Spreadfire Cannon",
94 //	"Plasma Cannon",
95 //	"Fusion Cannon"
96 //};
97 
98 //char	*Secondary_weapon_names[MAX_SECONDARY_WEAPONS] = {
99 //	"Concussion Missile",
100 //	"Homing Missile",
101 //	"Proximity Bomb",
102 //	"Smart Missile",
103 //	"Mega Missile"
104 //};
105 
106 //char	*Primary_weapon_names_short[MAX_PRIMARY_WEAPONS] = {
107 //	"Laser",
108 //	"Vulcan",
109 //	"Spread",
110 //	"Plasma",
111 //	"Fusion"
112 //};
113 
114 //char	*Secondary_weapon_names_short[MAX_SECONDARY_WEAPONS] = {
115 //	"Concsn\nMissile",
116 //	"Homing\nMissile",
117 //	"Proxim.\nBomb",
118 //	"Smart\nMissile",
119 //	"Mega\nMissile"
120 //};
121 
122 byte	Weapon_is_energy[MAX_WEAPON_TYPES] = {
123 	1, 1, 1, 1, 1,
124 	1, 1, 1, 0, 1,
125 	1, 0, 1, 1, 1,
126 	0, 1, 0, 0, 1,
127 	1, 0, 0, 1, 1,
128 	1, 1, 1, 0, 1,
129 	1, 1, 0, 1, 1,
130 	1
131 };
132 
133 // ; (0) Laser Level 1
134 // ; (1) Laser Level 2
135 // ; (2) Laser Level 3
136 // ; (3) Laser Level 4
137 // ; (4) Unknown Use
138 // ; (5) Josh Blobs
139 // ; (6) Unknown Use
140 // ; (7) Unknown Use
141 // ; (8) ---------- Concussion Missile ----------
142 // ; (9) ---------- Flare ----------
143 // ; (10) ---------- Blue laser that blue guy shoots -----------
144 // ; (11) ---------- Vulcan Cannon ----------
145 // ; (12) ---------- Spreadfire Cannon ----------
146 // ; (13) ---------- Plasma Cannon ----------
147 // ; (14) ---------- Fusion Cannon ----------
148 // ; (15) ---------- Homing Missile ----------
149 // ; (16) ---------- Proximity Bomb ----------
150 // ; (17) ---------- Smart Missile ----------
151 // ; (18) ---------- Mega Missile ----------
152 // ; (19) ---------- Children of the PLAYER'S Smart Missile ----------
153 // ; (20) ---------- Bad Guy Spreadfire Laser ----------
154 // ; (21) ---------- SuperMech Homing Missile ----------
155 // ; (22) ---------- Regular Mech's missile -----------
156 // ; (23) ---------- Silent Spreadfire Laser ----------
157 // ; (24) ---------- Red laser that baby spiders shoot -----------
158 // ; (25) ---------- Green laser that rifleman shoots -----------
159 // ; (26) ---------- Plasma gun that 'plasguy' fires ------------
160 // ; (27) ---------- Blobs fired by Red Spiders -----------
161 // ; (28) ---------- Final Boss's Mega Missile ----------
162 // ; (29) ---------- Children of the ROBOT'S Smart Missile ----------
163 // ; (30) Laser Level 5
164 // ; (31) Laser Level 6
165 // ; (32) ---------- Super Vulcan Cannon ----------
166 // ; (33) ---------- Super Spreadfire Cannon ----------
167 // ; (34) ---------- Super Plasma Cannon ----------
168 // ; (35) ---------- Super Fusion Cannon ----------
169 
170 //	------------------------------------------------------------------------------------
171 //	Return:
172 // Bits set:
173 //		HAS_WEAPON_FLAG
174 //		HAS_ENERGY_FLAG
175 //		HAS_AMMO_FLAG
176 // See weapon.h for bit values
player_has_weapon(int weapon_num,int secondary_flag)177 int player_has_weapon(int weapon_num, int secondary_flag)
178 {
179 	int	return_value = 0;
180 	int	weapon_index;
181 
182 	//	Hack! If energy goes negative, you can't fire a weapon that doesn't require energy.
183 	//	But energy should not go negative (but it does), so find out why it does!
184 	if (Players[Player_num].energy < 0)
185 		Players[Player_num].energy = 0;
186 
187 	if (!secondary_flag) {
188 		weapon_index = Primary_weapon_to_weapon_info[weapon_num];
189 
190 		if (Players[Player_num].primary_weapon_flags & (1 << weapon_num))
191 			return_value |= HAS_WEAPON_FLAG;
192 
193 		// Special case: Gauss cannon uses vulcan ammo.
194 		if (weapon_num == GAUSS_INDEX) {
195 			if (Weapon_info[weapon_index].ammo_usage <= Players[Player_num].primary_ammo[VULCAN_INDEX])
196 				return_value |= HAS_AMMO_FLAG;
197 		} else
198 			if (Weapon_info[weapon_index].ammo_usage <= Players[Player_num].primary_ammo[weapon_num])
199 				return_value |= HAS_AMMO_FLAG;
200 
201 		if (weapon_num == OMEGA_INDEX) {	// Hack: Make sure player has energy to omega
202 			if (Players[Player_num].energy || Omega_charge)
203 				return_value |= HAS_ENERGY_FLAG;
204 		} else
205 			if (Weapon_info[weapon_index].energy_usage <= Players[Player_num].energy)
206 				return_value |= HAS_ENERGY_FLAG;
207 
208 	} else {
209 		weapon_index = Secondary_weapon_to_weapon_info[weapon_num];
210 
211 		if (Players[Player_num].secondary_weapon_flags & (1 << weapon_num))
212 			return_value |= HAS_WEAPON_FLAG;
213 
214 		if (Weapon_info[weapon_index].ammo_usage <= Players[Player_num].secondary_ammo[weapon_num])
215 			return_value |= HAS_AMMO_FLAG;
216 
217 		if (Weapon_info[weapon_index].energy_usage <= Players[Player_num].energy)
218 			return_value |= HAS_ENERGY_FLAG;
219 	}
220 
221 	return return_value;
222 }
223 
InitWeaponOrdering()224 void InitWeaponOrdering ()
225  {
226   // short routine to setup default weapon priorities for new pilots
227 
228   int i;
229 
230   for (i=0;i<MAX_PRIMARY_WEAPONS+1;i++)
231 	PrimaryOrder[i]=DefaultPrimaryOrder[i];
232   for (i=0;i<MAX_SECONDARY_WEAPONS+1;i++)
233 	SecondaryOrder[i]=DefaultSecondaryOrder[i];
234  }
235 
CyclePrimary()236 void CyclePrimary ()
237 {
238 	mprintf ((0,"Cycling primary!\n"));
239 	Cycling=1;
240 	auto_select_weapon (0);
241 	Cycling=0;
242 }
243 
CycleSecondary()244 void CycleSecondary ()
245 {
246 	mprintf ((0,"Cycling secondary!\n"));
247 	Cycling=1;
248 	auto_select_weapon (1);
249 	Cycling=0;
250 }
251 
252 
253 //	------------------------------------------------------------------------------------
254 //if message flag set, print message saying selected
select_weapon(int weapon_num,int secondary_flag,int print_message,int wait_for_rearm)255 void select_weapon(int weapon_num, int secondary_flag, int print_message, int wait_for_rearm)
256 {
257 	char	*weapon_name;
258 
259 	if (Newdemo_state==ND_STATE_RECORDING )
260 		newdemo_record_player_weapon(secondary_flag, weapon_num);
261 
262 	if (!secondary_flag) {
263 		if (Primary_weapon != weapon_num) {
264 			if (wait_for_rearm) digi_play_sample_once( SOUND_GOOD_SELECTION_PRIMARY, F1_0 );
265 #ifdef NETWORK
266 			if (Game_mode & GM_MULTI)	{
267 				if (wait_for_rearm) multi_send_play_sound(SOUND_GOOD_SELECTION_PRIMARY, F1_0);
268 			}
269 #endif
270 			if (wait_for_rearm)
271 				Next_laser_fire_time = GameTime + REARM_TIME;
272 			else
273 				Next_laser_fire_time = 0;
274 			Global_laser_firing_count = 0;
275 		} else 	{
276 			// Select super version if available.
277 			if (wait_for_rearm)
278 			{
279 			 if (!Cycling)
280 				; // -- MK, only plays when can't fire weapon anyway, fixes bug -- digi_play_sample_once( SOUND_ALREADY_SELECTED, F1_0 );
281 			 else
282 				digi_play_sample_once( SOUND_BAD_SELECTION, F1_0 );
283 			}
284 		}
285 		Primary_weapon = weapon_num;
286 		weapon_name = PRIMARY_WEAPON_NAMES(weapon_num);
287       #if defined (TACTILE)
288  		tactile_set_button_jolt();
289 		#endif
290 
291 
292 		//save flag for whether was super version
293 		Primary_last_was_super[weapon_num % SUPER_WEAPON] = (weapon_num >= SUPER_WEAPON);
294 
295 	} else {
296 
297 		if (Secondary_weapon != weapon_num) {
298 			if (wait_for_rearm) digi_play_sample_once( SOUND_GOOD_SELECTION_SECONDARY, F1_0 );
299 #ifdef NETWORK
300 			if (Game_mode & GM_MULTI)	{
301 				if (wait_for_rearm) multi_send_play_sound(SOUND_GOOD_SELECTION_PRIMARY, F1_0);
302 			}
303 #endif
304 			if (wait_for_rearm)
305 				Next_missile_fire_time = GameTime + REARM_TIME;
306 			else
307 				Next_missile_fire_time = 0;
308 			Global_missile_firing_count = 0;
309 		} else	{
310 			if (wait_for_rearm)
311 			{
312 			 if (!Cycling)
313 				digi_play_sample_once( SOUND_ALREADY_SELECTED, F1_0 );
314 			 else
315 				digi_play_sample_once( SOUND_BAD_SELECTION, F1_0 );
316 			}
317 
318 		}
319 		Secondary_weapon = weapon_num;
320 		weapon_name = SECONDARY_WEAPON_NAMES(weapon_num);
321 
322 		//save flag for whether was super version
323 		Secondary_last_was_super[weapon_num % SUPER_WEAPON] = (weapon_num >= SUPER_WEAPON);
324 	}
325 
326 	if (print_message)
327 	{
328 		if (weapon_num == LASER_INDEX && !secondary_flag)
329 			HUD_init_message("%s Level %d %s", weapon_name, Players[Player_num].laser_level+1, TXT_SELECTED);
330 		else
331 			HUD_init_message("%s %s", weapon_name, TXT_SELECTED);
332 	}
333 
334 }
335 
336 //flags whether the last time we use this weapon, it was the 'super' version
337 ubyte Primary_last_was_super[MAX_PRIMARY_WEAPONS];
338 ubyte Secondary_last_was_super[MAX_SECONDARY_WEAPONS];
339 
340 //	------------------------------------------------------------------------------------
341 //	Select a weapon, primary or secondary.
do_weapon_select(int weapon_num,int secondary_flag)342 void do_weapon_select(int weapon_num, int secondary_flag)
343 {
344 	int	weapon_num_save=weapon_num;
345 	int	weapon_status,current,has_flag;
346 	ubyte	last_was_super;
347 
348 	if (!secondary_flag) {
349 		current = Primary_weapon;
350 		last_was_super = Primary_last_was_super[weapon_num];
351 		has_flag = HAS_WEAPON_FLAG;
352 	}
353 	else {
354 		current = Secondary_weapon;
355 		last_was_super = Secondary_last_was_super[weapon_num];
356 		has_flag = HAS_WEAPON_FLAG+HAS_AMMO_FLAG;
357 	}
358 
359 	if (current == weapon_num || current == weapon_num+SUPER_WEAPON) {
360 
361 		//already have this selected, so toggle to other of normal/super version
362 
363 		weapon_num += weapon_num+SUPER_WEAPON - current;
364 		weapon_status = player_has_weapon(weapon_num, secondary_flag);
365 	}
366 	else {
367 
368 		//go to last-select version of requested missile
369 
370 		if (last_was_super)
371 			weapon_num += SUPER_WEAPON;
372 
373 		weapon_status = player_has_weapon(weapon_num, secondary_flag);
374 
375 		//if don't have last-selected, try other version
376 
377 		if ((weapon_status & has_flag) != has_flag) {
378 			weapon_num = 2*weapon_num_save+SUPER_WEAPON - weapon_num;
379 			weapon_status = player_has_weapon(weapon_num, secondary_flag);
380 			if ((weapon_status & has_flag) != has_flag)
381 				weapon_num = 2*weapon_num_save+SUPER_WEAPON - weapon_num;
382 		}
383 	}
384 
385 	//if we don't have the weapon we're switching to, give error & bail
386 	if ((weapon_status & has_flag) != has_flag) {
387 		if (!secondary_flag) {
388 			if (weapon_num==SUPER_LASER_INDEX)
389 				return; 		//no such thing as super laser, so no error
390 			HUD_init_message("%s %s!", TXT_DONT_HAVE, PRIMARY_WEAPON_NAMES(weapon_num));
391 		}
392 		else
393 			HUD_init_message("%s %s%s",TXT_HAVE_NO, SECONDARY_WEAPON_NAMES(weapon_num), TXT_SX);
394 		digi_play_sample( SOUND_BAD_SELECTION, F1_0 );
395 		return;
396 	}
397 
398 	//now actually select the weapon
399 	select_weapon(weapon_num, secondary_flag, 1, 1);
400 }
401 
402 //	----------------------------------------------------------------------------------------
403 //	Automatically select next best weapon if unable to fire current weapon.
404 // Weapon type: 0==primary, 1==secondary
auto_select_weapon(int weapon_type)405 void auto_select_weapon(int weapon_type)
406 {
407 	int	r;
408 	int cutpoint;
409 	int looped=0;
410 
411 	if (weapon_type==0) {
412 		r = player_has_weapon(Primary_weapon, 0);
413 		if (r != HAS_ALL || Cycling) {
414 			int	cur_weapon;
415 			int	try_again = 1;
416 
417 			cur_weapon = POrderList(Primary_weapon);
418 			cutpoint = POrderList (255);
419 
420 			while (try_again) {
421 				cur_weapon++;
422 
423 				if (cur_weapon>=cutpoint)
424 				{
425 					if (looped)
426 					{
427 						if (!Cycling)
428 						{
429 							HUD_init_message(TXT_NO_PRIMARY);
430 							#ifdef TACTILE
431 							if (TactileStick)
432 							 ButtonReflexClear(0);
433 							#endif
434 							select_weapon(0, 0, 0, 1);
435 						}
436 						else
437 							select_weapon (Primary_weapon,0,0,1);
438 
439 						try_again = 0;
440 						continue;
441 					}
442 					cur_weapon=0;
443 					looped=1;
444 				}
445 
446 
447 				if (cur_weapon==MAX_PRIMARY_WEAPONS)
448 					cur_weapon = 0;
449 
450 				//	Hack alert!  Because the fusion uses 0 energy at the end (it's got the weird chargeup)
451 				//	it looks like it takes 0 to fire, but it doesn't, so never auto-select.
452 				// if (PrimaryOrder[cur_weapon] == FUSION_INDEX)
453 				//	continue;
454 
455 				if (PrimaryOrder[cur_weapon] == Primary_weapon) {
456 					if (!Cycling)
457 					{
458 						HUD_init_message(TXT_NO_PRIMARY);
459 						#ifdef TACTILE
460 						if (TactileStick)
461 						 ButtonReflexClear(0);
462 						#endif
463 
464 						//	if (POrderList(0)<POrderList(255))
465 						select_weapon(0, 0, 0, 1);
466 					}
467 					else
468 						select_weapon (Primary_weapon,0,0,1);
469 
470 					try_again = 0;			// Tried all weapons!
471 
472 				} else if (PrimaryOrder[cur_weapon]!=255 && player_has_weapon(PrimaryOrder[cur_weapon], 0) == HAS_ALL) {
473 					select_weapon(PrimaryOrder[cur_weapon], 0, 1, 1 );
474 					try_again = 0;
475 				}
476 			}
477 		}
478 
479 	} else {
480 
481 		Assert(weapon_type==1);
482 		r = player_has_weapon(Secondary_weapon, 1);
483 		if (r != HAS_ALL || Cycling) {
484 			int	cur_weapon;
485 			int	try_again = 1;
486 
487 			cur_weapon = SOrderList(Secondary_weapon);
488 			cutpoint = SOrderList (255);
489 
490 
491 			while (try_again) {
492 				cur_weapon++;
493 
494 				if (cur_weapon>=cutpoint)
495 				{
496 					if (looped)
497 					{
498 						if (!Cycling)
499 							HUD_init_message("No secondary weapons selected!");
500 						else
501 							select_weapon (Secondary_weapon,1,0,1);
502 						try_again = 0;
503 						continue;
504 					}
505 					cur_weapon=0;
506 					looped=1;
507 				}
508 
509 				if (cur_weapon==MAX_SECONDARY_WEAPONS)
510 					cur_weapon = 0;
511 
512 				if (SecondaryOrder[cur_weapon] == Secondary_weapon) {
513 					if (!Cycling)
514 						HUD_init_message("No secondary weapons available!");
515 					else
516 						select_weapon (Secondary_weapon,1,0,1);
517 
518 					try_again = 0;				// Tried all weapons!
519 				} else if (player_has_weapon(SecondaryOrder[cur_weapon], 1) == HAS_ALL) {
520 					select_weapon(SecondaryOrder[cur_weapon], 1, 1, 1 );
521 					try_again = 0;
522 				}
523 			}
524 		}
525 
526 
527 	}
528 
529 }
530 
531 #ifndef RELEASE
532 
533 //	----------------------------------------------------------------------------------------
534 //	Show player which weapons he has, how much ammo...
535 //	Looks like a debug screen now because it writes to mono screen, but that will change...
show_weapon_status(void)536 void show_weapon_status(void)
537 {
538 	int	i;
539 
540 	for (i=0; i<MAX_PRIMARY_WEAPONS; i++) {
541 		if (Players[Player_num].primary_weapon_flags & (1 << i))
542 			mprintf((0, "HAVE"));
543 		else
544 			mprintf((0, "    "));
545 
546 		mprintf((0, "  Weapon: %20s, charges: %4i\n", PRIMARY_WEAPON_NAMES(i), Players[Player_num].primary_ammo[i]));
547 	}
548 
549 	mprintf((0, "\n"));
550 	for (i=0; i<MAX_SECONDARY_WEAPONS; i++) {
551 		if (Players[Player_num].secondary_weapon_flags & (1 << i))
552 			mprintf((0, "HAVE"));
553 		else
554 			mprintf((0, "    "));
555 
556 		mprintf((0, "  Weapon: %20s, charges: %4i\n", SECONDARY_WEAPON_NAMES(i), Players[Player_num].secondary_ammo[i]));
557 	}
558 
559 	mprintf((0, "\n"));
560 	mprintf((0, "\n"));
561 
562 }
563 
564 #endif
565 
566 //	---------------------------------------------------------------------
567 //called when one of these weapons is picked up
568 //when you pick up a secondary, you always get the weapon & ammo for it
569 //	Returns true if powerup picked up, else returns false.
pick_up_secondary(int weapon_index,int count)570 int pick_up_secondary(int weapon_index,int count)
571 {
572 	int max;
573 	int	num_picked_up;
574 	int cutpoint;
575 
576 	max = Secondary_ammo_max[weapon_index];
577 
578 	if (Players[Player_num].flags & PLAYER_FLAGS_AMMO_RACK)
579 		max *= 2;
580 
581 	if (Players[Player_num].secondary_ammo[weapon_index] >= max) {
582 		HUD_init_message("%s %i %ss!", TXT_ALREADY_HAVE, Players[Player_num].secondary_ammo[weapon_index],SECONDARY_WEAPON_NAMES(weapon_index));
583 		return 0;
584 	}
585 
586 	Players[Player_num].secondary_weapon_flags |= (1<<weapon_index);
587 	Players[Player_num].secondary_ammo[weapon_index] += count;
588 
589 	num_picked_up = count;
590 	if (Players[Player_num].secondary_ammo[weapon_index] > max) {
591 		num_picked_up = count - (Players[Player_num].secondary_ammo[weapon_index] - max);
592 		Players[Player_num].secondary_ammo[weapon_index] = max;
593 	}
594 
595 	cutpoint=SOrderList (255);
596 	if (SOrderList (weapon_index)<cutpoint && ((SOrderList (weapon_index) < SOrderList(Secondary_weapon)) || (Players[Player_num].secondary_ammo[Secondary_weapon] == 0))   )
597 		select_weapon(weapon_index,1, 0, 1);
598 	else {
599 		//if we don't auto-select this weapon, but it's a proxbomb or smart mine,
600 		//we want to do a mini-auto-selection that applies to the drop bomb key
601 
602 		if ((weapon_index == PROXIMITY_INDEX || weapon_index == SMART_MINE_INDEX) &&
603 				!(Secondary_weapon == PROXIMITY_INDEX || Secondary_weapon == SMART_MINE_INDEX)) {
604 			int cur;
605 
606 			cur = Secondary_last_was_super[PROXIMITY_INDEX]?SMART_MINE_INDEX:PROXIMITY_INDEX;
607 
608 			if (SOrderList (weapon_index) < SOrderList(cur))
609 				Secondary_last_was_super[PROXIMITY_INDEX] = (weapon_index == SMART_MINE_INDEX);
610 		}
611 	}
612 
613 	//note: flash for all but concussion was 7,14,21
614 	if (count>1) {
615 		PALETTE_FLASH_ADD(15,15,15);
616 		HUD_init_message("%d %s%s",num_picked_up,SECONDARY_WEAPON_NAMES(weapon_index), TXT_SX);
617 	}
618 	else {
619 		PALETTE_FLASH_ADD(10,10,10);
620 		HUD_init_message("%s!",SECONDARY_WEAPON_NAMES(weapon_index));
621 	}
622 
623 	return 1;
624 }
625 
ReorderPrimary()626 void ReorderPrimary ()
627 {
628 	newmenu_item m[MAX_PRIMARY_WEAPONS+1];
629 	int i;
630 
631 	for (i=0;i<MAX_PRIMARY_WEAPONS+1;i++)
632 	{
633 		m[i].type=NM_TYPE_MENU;
634 		if (PrimaryOrder[i]==255)
635 			m[i].text="������� Never autoselect �������";
636 		else
637 			m[i].text=(char *)PRIMARY_WEAPON_NAMES(PrimaryOrder[i]);
638 		m[i].value=PrimaryOrder[i];
639 	}
640 	MenuReordering=1;
641 	i = newmenu_do("Reorder Primary","Shift+Up/Down arrow to move item", i, m, NULL);
642 	MenuReordering=0;
643 
644 	for (i=0;i<MAX_PRIMARY_WEAPONS+1;i++)
645 		PrimaryOrder[i]=m[i].value;
646 }
647 
ReorderSecondary()648 void ReorderSecondary ()
649 {
650 	newmenu_item m[MAX_SECONDARY_WEAPONS+1];
651 	int i;
652 
653 	for (i=0;i<MAX_SECONDARY_WEAPONS+1;i++)
654 	{
655 		m[i].type=NM_TYPE_MENU;
656 		if (SecondaryOrder[i]==255)
657 			m[i].text="������� Never autoselect �������";
658 		else
659 			m[i].text=(char *)SECONDARY_WEAPON_NAMES(SecondaryOrder[i]);
660 		m[i].value=SecondaryOrder[i];
661 	}
662 	MenuReordering=1;
663 	i = newmenu_do("Reorder Secondary","Shift+Up/Down arrow to move item", i, m, NULL);
664 	MenuReordering=0;
665 	for (i=0;i<MAX_SECONDARY_WEAPONS+1;i++)
666 		SecondaryOrder[i]=m[i].value;
667 }
668 
POrderList(int num)669 int POrderList (int num)
670 {
671 	int i;
672 
673 	for (i=0;i<MAX_PRIMARY_WEAPONS+1;i++)
674 	if (PrimaryOrder[i]==num)
675 	{
676 		mprintf ((0,"Primary %d has priority of %d!\n",num,i));
677 		return (i);
678 	}
679 	Error ("Primary Weapon is not in order list!!!");
680 }
681 
SOrderList(int num)682 int SOrderList (int num)
683 {
684 	int i;
685 
686 	for (i=0;i<MAX_SECONDARY_WEAPONS+1;i++)
687 		if (SecondaryOrder[i]==num)
688 		{
689 			mprintf ((0,"Secondary %d has priority of %d!\n",num,i));
690 			return (i);
691 		}
692 	mprintf ((0,"Error! Secondary Num=%d\n",num));
693 	Error ("Secondary Weapon is not in order list!!!");
694 }
695 
696 
697 //called when a primary weapon is picked up
698 //returns true if actually picked up
pick_up_primary(int weapon_index)699 int pick_up_primary(int weapon_index)
700 {
701 	//ushort old_flags = Players[Player_num].primary_weapon_flags;
702 	ushort flag = 1<<weapon_index;
703 	int cutpoint;
704 	int supposed_weapon=Primary_weapon;
705 
706 	if (weapon_index!=LASER_INDEX && Players[Player_num].primary_weapon_flags & flag) {		//already have
707 		HUD_init_message("%s %s!", TXT_ALREADY_HAVE_THE, PRIMARY_WEAPON_NAMES(weapon_index));
708 		return 0;
709 	}
710 
711 	Players[Player_num].primary_weapon_flags |= flag;
712 
713 	cutpoint=POrderList (255);
714 
715 	if (Primary_weapon==LASER_INDEX && Players[Player_num].laser_level>=4)
716 		supposed_weapon=SUPER_LASER_INDEX;  // allotment for stupid way of doing super laser
717 
718 
719 	if (POrderList(weapon_index)<cutpoint && POrderList(weapon_index)<POrderList(supposed_weapon))
720 		select_weapon(weapon_index,0,0,1);
721 
722 	PALETTE_FLASH_ADD(7,14,21);
723 	mprintf ((0,"Weapon index: %d\n",weapon_index));
724 
725    if (weapon_index!=LASER_INDEX)
726    	HUD_init_message("%s!",PRIMARY_WEAPON_NAMES(weapon_index));
727 
728 	return 1;
729 }
check_to_use_primary(int weapon_index)730 int check_to_use_primary(int weapon_index)
731 {
732 	ushort old_flags = Players[Player_num].primary_weapon_flags;
733 	ushort flag = 1<<weapon_index;
734 	int cutpoint;
735 
736 	cutpoint=POrderList (255);
737 
738 	if (!(old_flags & flag) && POrderList(weapon_index)<cutpoint && POrderList(weapon_index)<POrderList(Primary_weapon))
739 	{
740 		if (weapon_index==SUPER_LASER_INDEX)
741 			select_weapon(LASER_INDEX,0,0,1);
742 		else
743 			select_weapon(weapon_index,0,0,1);
744 	}
745 
746 	PALETTE_FLASH_ADD(7,14,21);
747 
748 	return 1;
749 }
750 
751 
752 
753 //called when ammo (for the vulcan cannon) is picked up
754 //	Returns the amount picked up
pick_up_ammo(int class_flag,int weapon_index,int ammo_count)755 int pick_up_ammo(int class_flag,int weapon_index,int ammo_count)
756 {
757 	int max,cutpoint,supposed_weapon=Primary_weapon;
758 	int old_ammo=class_flag;		//kill warning
759 
760 	Assert(class_flag==CLASS_PRIMARY && weapon_index==VULCAN_INDEX);
761 
762 	max = Primary_ammo_max[weapon_index];
763 	if (Players[Player_num].flags & PLAYER_FLAGS_AMMO_RACK)
764 		max *= 2;
765 
766 	if (Players[Player_num].primary_ammo[weapon_index] == max)
767 		return 0;
768 
769 	old_ammo = Players[Player_num].primary_ammo[weapon_index];
770 
771 	Players[Player_num].primary_ammo[weapon_index] += ammo_count;
772 
773 	if (Players[Player_num].primary_ammo[weapon_index] > max) {
774 		ammo_count += (max - Players[Player_num].primary_ammo[weapon_index]);
775 		Players[Player_num].primary_ammo[weapon_index] = max;
776 	}
777 	cutpoint=POrderList (255);
778 
779 	if (Primary_weapon==LASER_INDEX && Players[Player_num].laser_level>=4)
780 		supposed_weapon=SUPER_LASER_INDEX;  // allotment for stupid way of doing super laser
781 
782 
783 	if (Players[Player_num].primary_weapon_flags&(1<<weapon_index) && weapon_index>Primary_weapon && old_ammo==0 &&
784 		POrderList(weapon_index)<cutpoint && POrderList(weapon_index)<POrderList(supposed_weapon))
785 		select_weapon(weapon_index,0,0,1);
786 
787 	return ammo_count;	//return amount used
788 }
789 
790 #define	SMEGA_SHAKE_TIME		(F1_0*2)
791 #define	MAX_SMEGA_DETONATES	4
792 fix	Smega_detonate_times[MAX_SMEGA_DETONATES];
793 
794 //	Call this to initialize for a new level.
795 //	Sets all super mega missile detonation times to 0 which means there aren't any.
init_smega_detonates(void)796 void init_smega_detonates(void)
797 {
798 	int	i;
799 
800 	for (i=0; i<MAX_SMEGA_DETONATES; i++)
801 		Smega_detonate_times[i] = 0;
802 }
803 
804 fix	Seismic_tremor_magnitude;
805 fix	Next_seismic_sound_time;
806 int	Seismic_sound_playing = 0;
807 int	Seismic_tremor_volume;
808 
809 int	Seismic_sound = SOUND_SEISMIC_DISTURBANCE_START;
810 
811 //	If a smega missile been detonated, rock the mine!
812 //	This should be called every frame.
813 //	Maybe this should affect all robots, being called when they get their physics done.
rock_the_mine_frame(void)814 void rock_the_mine_frame(void)
815 {
816 	int	i;
817 
818 	for (i=0; i<MAX_SMEGA_DETONATES; i++) {
819 
820 		if (Smega_detonate_times[i] != 0) {
821 			fix	delta_time;
822 			delta_time = GameTime - Smega_detonate_times[i];
823 
824 			if (!Seismic_sound_playing) {
825 				digi_play_sample_looping(Seismic_sound, F1_0, -1, -1);
826 				Seismic_sound_playing = 1;
827 				Next_seismic_sound_time = GameTime + d_rand()/2;
828 			}
829 
830 			if (delta_time < SMEGA_SHAKE_TIME) {
831 
832 				//	Control center destroyed, rock the player's ship.
833 				int	fc, rx, rz;
834 				// -- fc = abs(delta_time - SMEGA_SHAKE_TIME/2);
835 				//	Changed 10/23/95 to make decreasing for super mega missile.
836 				fc = (SMEGA_SHAKE_TIME - delta_time)/2;
837 				fc /= SMEGA_SHAKE_TIME/32;
838 				if (fc > 16)
839 					fc = 16;
840 
841 				if (fc == 0)
842 					fc = 1;
843 
844 				Seismic_tremor_volume += fc;
845 
846 				rx = fixmul(d_rand() - 16384, 3*F1_0/16 + (F1_0*(16-fc))/32);
847 				rz = fixmul(d_rand() - 16384, 3*F1_0/16 + (F1_0*(16-fc))/32);
848 
849 				ConsoleObject->mtype.phys_info.rotvel.x += rx;
850 				ConsoleObject->mtype.phys_info.rotvel.z += rz;
851 
852 				//	Shake the buddy!
853 				if (Buddy_objnum != -1) {
854 					Objects[Buddy_objnum].mtype.phys_info.rotvel.x += rx*4;
855 					Objects[Buddy_objnum].mtype.phys_info.rotvel.z += rz*4;
856 				}
857 
858 				//	Shake a guided missile!
859 				Seismic_tremor_magnitude += rx;
860 
861 			} else
862 				Smega_detonate_times[i] = 0;
863 
864 		}
865 	}
866 
867 	//	Hook in the rumble sound effect here.
868 }
869 
870 extern	int	Level_shake_frequency, Level_shake_duration;
871 #ifdef NETWORK
872 extern void multi_send_seismic (fix,fix);
873 #endif
874 
875 #define	SEISMIC_DISTURBANCE_DURATION	(F1_0*5)
876 fix	Seismic_disturbance_start_time = 0, Seismic_disturbance_end_time;
877 
878 int Seismic_level=0;
879 
on_seismic_level(void)880 int	on_seismic_level(void)
881 {
882 	return Seismic_level;
883 }
884 
init_seismic_disturbances(void)885 void init_seismic_disturbances(void)
886 {
887 	Seismic_disturbance_start_time = 0;
888 	Seismic_disturbance_end_time = 0;
889 }
890 
891 //	Return true if time to start a seismic disturbance.
start_seismic_disturbance(void)892 int start_seismic_disturbance(void)
893 {
894 	int	rval;
895 
896 	if (Level_shake_duration < 1)
897 		return 0;
898 
899 	rval =  (2 * fixmul(d_rand(), Level_shake_frequency)) < FrameTime;
900 
901 	if (rval) {
902 		Seismic_disturbance_start_time = GameTime;
903 		Seismic_disturbance_end_time = GameTime + Level_shake_duration;
904 		if (!Seismic_sound_playing) {
905 			digi_play_sample_looping(Seismic_sound, F1_0, -1, -1);
906 			Seismic_sound_playing = 1;
907 			Next_seismic_sound_time = GameTime + d_rand()/2;
908 		}
909 
910 #ifdef NETWORK
911 		if (Game_mode & GM_MULTI)
912 			multi_send_seismic (Seismic_disturbance_start_time,Seismic_disturbance_end_time);
913 #endif
914 	}
915 
916 	return rval;
917 }
918 
seismic_disturbance_frame(void)919 void seismic_disturbance_frame(void)
920 {
921 	if (Level_shake_frequency) {
922 		if (((Seismic_disturbance_start_time < GameTime) && (Seismic_disturbance_end_time > GameTime)) || start_seismic_disturbance()) {
923 			fix	delta_time;
924 			int	fc, rx, rz;
925 
926 			delta_time = GameTime - Seismic_disturbance_start_time;
927 
928 			fc = abs(delta_time - (Seismic_disturbance_end_time - Seismic_disturbance_start_time)/2);
929 			fc /= F1_0/16;
930 			if (fc > 16)
931 				fc = 16;
932 
933 			if (fc == 0)
934 				fc = 1;
935 
936 			Seismic_tremor_volume += fc;
937 
938 			rx = fixmul(d_rand() - 16384, 3*F1_0/16 + (F1_0*(16-fc))/32);
939 			rz = fixmul(d_rand() - 16384, 3*F1_0/16 + (F1_0*(16-fc))/32);
940 
941 			ConsoleObject->mtype.phys_info.rotvel.x += rx;
942 			ConsoleObject->mtype.phys_info.rotvel.z += rz;
943 
944 			//	Shake the buddy!
945 			if (Buddy_objnum != -1) {
946 				Objects[Buddy_objnum].mtype.phys_info.rotvel.x += rx*4;
947 				Objects[Buddy_objnum].mtype.phys_info.rotvel.z += rz*4;
948 			}
949 
950 			//	Shake a guided missile!
951 			Seismic_tremor_magnitude += rx;
952 		}
953 	}
954 }
955 
956 
957 //	Call this when a smega detonates to start the process of rocking the mine.
smega_rock_stuff(void)958 void smega_rock_stuff(void)
959 {
960 	int	i;
961 
962 	for (i=0; i<MAX_SMEGA_DETONATES; i++) {
963 		if (Smega_detonate_times[i] + SMEGA_SHAKE_TIME < GameTime)
964 			Smega_detonate_times[i] = 0;
965 	}
966 
967 	for (i=0; i<MAX_SMEGA_DETONATES; i++) {
968 		if (Smega_detonate_times[i] == 0) {
969 			Smega_detonate_times[i] = GameTime;
970 			break;
971 		}
972 	}
973 }
974 
975 int	Super_mines_yes = 1;
976 
977 //	Call this once/frame to process all super mines in the level.
process_super_mines_frame(void)978 void process_super_mines_frame(void)
979 {
980 	int	i, j;
981 	int	start, add;
982 
983 	//	If we don't know of there being any super mines in the level, just
984 	//	check every 8th object each frame.
985 	if (Super_mines_yes == 0) {
986 		start = FrameCount & 7;
987 		add = 8;
988 	} else {
989 		start = 0;
990 		add = 1;
991 	}
992 
993 	Super_mines_yes = 0;
994 
995 	for (i=start; i<=Highest_object_index; i+=add) {
996 		if ((Objects[i].type == OBJ_WEAPON) && (Objects[i].id == SUPERPROX_ID)) {
997 			int	parent_num;
998 
999 			parent_num = Objects[i].ctype.laser_info.parent_num;
1000 
1001 			Super_mines_yes = 1;
1002 			if (Objects[i].lifeleft + F1_0*2 < Weapon_info[SUPERPROX_ID].lifetime) {
1003 				vms_vector	*bombpos;
1004 
1005 				bombpos = &Objects[i].pos;
1006 
1007 				for (j=0; j<=Highest_object_index; j++) {
1008 					if ((Objects[j].type == OBJ_PLAYER) || (Objects[j].type == OBJ_ROBOT)) {
1009 						fix	dist;
1010 
1011 						dist = vm_vec_dist_quick(bombpos, &Objects[j].pos);
1012 
1013 						if (j != parent_num)
1014 							if (dist - Objects[j].size < F1_0*20)
1015 							{
1016 								if (Objects[i].segnum == Objects[j].segnum)
1017 									Objects[i].lifeleft = 1;
1018 								else {
1019 									//	Object which is close enough to detonate smart mine is not in same segment as smart mine.
1020 									//	Need to do a more expensive check to make sure there isn't an obstruction.
1021 									if (((FrameCount ^ (i+j)) % 4) == 0) {
1022 										fvi_query	fq;
1023 										fvi_info		hit_data;
1024 										int			fate;
1025 
1026 										mprintf((0, "Expensive proxmine collision check.  Frame %i\n", FrameCount));
1027 
1028 										fq.startseg = Objects[i].segnum;
1029 										fq.p0						= &Objects[i].pos;
1030 										fq.p1						= &Objects[j].pos;
1031 										fq.rad					= 0;
1032 										fq.thisobjnum			= i;
1033 										fq.ignore_obj_list	= NULL;
1034 										fq.flags					= 0;
1035 
1036 										fate = find_vector_intersection(&fq, &hit_data);
1037 										if (fate != HIT_WALL)
1038 											Objects[i].lifeleft = 1;
1039 									}
1040 								}
1041 							}
1042 					}
1043 				}
1044 			}
1045 		}
1046 	}
1047 
1048 }
1049 
1050 #define SPIT_SPEED 20
1051 
1052 //this function is for when the player intentionally drops a powerup
1053 //this function is based on drop_powerup()
spit_powerup(object * spitter,int id,int seed)1054 int spit_powerup(object *spitter, int id,int seed)
1055 {
1056 	int		objnum;
1057 	object	*obj;
1058 	vms_vector	new_velocity, new_pos;
1059 
1060 	d_srand(seed);
1061 
1062 	vm_vec_scale_add(&new_velocity,&spitter->mtype.phys_info.velocity,&spitter->orient.fvec,i2f(SPIT_SPEED));
1063 
1064 	new_velocity.x += (d_rand() - 16384) * SPIT_SPEED * 2;
1065 	new_velocity.y += (d_rand() - 16384) * SPIT_SPEED * 2;
1066 	new_velocity.z += (d_rand() - 16384) * SPIT_SPEED * 2;
1067 
1068 	// Give keys zero velocity so they can be tracked better in multi
1069 
1070 	if ((Game_mode & GM_MULTI) && (id >= POW_KEY_BLUE) && (id <= POW_KEY_GOLD))
1071 		vm_vec_zero(&new_velocity);
1072 
1073 	//there's a piece of code which lets the player pick up a powerup if
1074 	//the distance between him and the powerup is less than 2 time their
1075 	//combined radii.  So we need to create powerups pretty far out from
1076 	//the player.
1077 
1078 	vm_vec_scale_add(&new_pos,&spitter->pos,&spitter->orient.fvec,spitter->size);
1079 
1080 #ifdef NETWORK
1081 	if (Game_mode & GM_MULTI)
1082 	{
1083 		if (Net_create_loc >= MAX_NET_CREATE_OBJECTS)
1084 		{
1085 			mprintf( (0, "WEAPON:Not enough slots to drop all powerups!\n" ));
1086 			return (-1);
1087 		}
1088 	}
1089 #endif
1090 
1091 	objnum = obj_create( OBJ_POWERUP, id, spitter->segnum, &new_pos, &vmd_identity_matrix, Powerup_info[id].size, CT_POWERUP, MT_PHYSICS, RT_POWERUP);
1092 
1093 	if (objnum < 0 ) {
1094 		mprintf((1, "Can't create object in object_create_egg.  Aborting.\n"));
1095 		Int3();
1096 		return objnum;
1097 	}
1098 
1099 	obj = &Objects[objnum];
1100 
1101 	obj->mtype.phys_info.velocity = new_velocity;
1102 	obj->mtype.phys_info.drag = 512;	//1024;
1103 	obj->mtype.phys_info.mass = F1_0;
1104 
1105 	obj->mtype.phys_info.flags = PF_BOUNCE;
1106 
1107 	obj->rtype.vclip_info.vclip_num = Powerup_info[obj->id].vclip_num;
1108 	obj->rtype.vclip_info.frametime = Vclip[obj->rtype.vclip_info.vclip_num].frame_time;
1109 	obj->rtype.vclip_info.framenum = 0;
1110 
1111 	if (spitter == ConsoleObject)
1112 		obj->ctype.powerup_info.flags |= PF_SPAT_BY_PLAYER;
1113 
1114 	switch (obj->id) {
1115 		case POW_MISSILE_1:
1116 		case POW_MISSILE_4:
1117 		case POW_SHIELD_BOOST:
1118 		case POW_ENERGY:
1119 			obj->lifeleft = (d_rand() + F1_0*3) * 64;		//	Lives for 3 to 3.5 binary minutes (a binary minute is 64 seconds)
1120 			if (Game_mode & GM_MULTI)
1121 				obj->lifeleft /= 2;
1122 			break;
1123 		default:
1124 			//if (Game_mode & GM_MULTI)
1125 			//	obj->lifeleft = (d_rand() + F1_0*3) * 64;		//	Lives for 5 to 5.5 binary minutes (a binary minute is 64 seconds)
1126 			break;
1127 	}
1128 
1129 	return objnum;
1130 }
1131 
DropCurrentWeapon()1132 void DropCurrentWeapon ()
1133 {
1134 	int objnum,ammo=0,seed;
1135 
1136 	if (Primary_weapon==0)
1137 	{
1138 		HUD_init_message("You cannot drop your base weapon!");
1139 		return;
1140 	}
1141 
1142 	HUD_init_message("%s dropped!",PRIMARY_WEAPON_NAMES(Primary_weapon));
1143 	digi_play_sample (SOUND_DROP_WEAPON,F1_0);
1144 
1145 	seed = d_rand();
1146 
1147 	objnum = spit_powerup(ConsoleObject,Primary_weapon_to_powerup[Primary_weapon],seed);
1148 
1149    if (objnum<0)
1150 		return;
1151 
1152 	if (Primary_weapon == VULCAN_INDEX || Primary_weapon == GAUSS_INDEX) {
1153 
1154 		//if it's one of these, drop some ammo with the weapon
1155 
1156 		ammo = Players[Player_num].primary_ammo[VULCAN_INDEX];
1157 
1158 		if ((Players[Player_num].primary_weapon_flags & HAS_FLAG(VULCAN_INDEX)) && (Players[Player_num].primary_weapon_flags & HAS_FLAG(GAUSS_INDEX)))
1159 			ammo /= 2;		//if both vulcan & gauss, drop half
1160 
1161 		Players[Player_num].primary_ammo[VULCAN_INDEX] -= ammo;
1162 
1163 		if (objnum!=-1)
1164 			Objects[objnum].ctype.powerup_info.count = ammo;
1165 	}
1166 
1167 	if (Primary_weapon == OMEGA_INDEX) {
1168 
1169 		//dropped weapon has current energy
1170 
1171 		if (objnum!=-1)
1172 			Objects[objnum].ctype.powerup_info.count = Omega_charge;
1173 	}
1174 
1175 #ifdef NETWORK
1176 	if ((Game_mode & GM_MULTI) && objnum>-1)
1177 		multi_send_drop_weapon(objnum,seed);
1178 #endif
1179 
1180 	Players[Player_num].primary_weapon_flags &= (~(1<<Primary_weapon));
1181 	auto_select_weapon (0);
1182 }
1183 
1184 
DropSecondaryWeapon()1185 void DropSecondaryWeapon ()
1186 {
1187 	int objnum,seed;
1188 
1189 	if (Players[Player_num].secondary_ammo[Secondary_weapon] ==0)
1190 	{
1191 		HUD_init_message("No secondary weapon to drop!");
1192 		return;
1193 	}
1194 
1195 	if ((Secondary_weapon_to_powerup[Secondary_weapon]==POW_PROXIMITY_WEAPON ||
1196 		Secondary_weapon_to_powerup[Secondary_weapon]==POW_SMART_MINE) &&
1197 		Players[Player_num].secondary_ammo[Secondary_weapon]<4)
1198 	{
1199 		HUD_init_message("You need at least 4 to drop!");
1200 		return;
1201 	}
1202 
1203 	HUD_init_message("%s dropped!",SECONDARY_WEAPON_NAMES(Secondary_weapon));
1204 	digi_play_sample (SOUND_DROP_WEAPON,F1_0);
1205 
1206 	seed = d_rand();
1207 
1208 	objnum = spit_powerup(ConsoleObject,Secondary_weapon_to_powerup[Secondary_weapon],seed);
1209 
1210    if (objnum<0)
1211 		return;
1212 
1213 
1214 #ifdef NETWORK
1215 	if ((Game_mode & GM_MULTI) && objnum>-1)
1216 		multi_send_drop_weapon(objnum,seed);
1217 #endif
1218 
1219 	if (Secondary_weapon_to_powerup[Secondary_weapon]==POW_PROXIMITY_WEAPON ||
1220 		Secondary_weapon_to_powerup[Secondary_weapon]==POW_SMART_MINE)
1221 		Players[Player_num].secondary_ammo[Secondary_weapon]-=4;
1222 	else
1223 		Players[Player_num].secondary_ammo[Secondary_weapon]--;
1224 
1225 	if (Players[Player_num].secondary_ammo[Secondary_weapon]==0)
1226 	{
1227 		Players[Player_num].secondary_weapon_flags &= (~(1<<Secondary_weapon));
1228 		auto_select_weapon (1);
1229 	}
1230 }
1231 
1232 //	---------------------------------------------------------------------------------------
1233 //	Do seismic disturbance stuff including the looping sounds with changing volume.
do_seismic_stuff(void)1234 void do_seismic_stuff(void)
1235 {
1236 	int	stv_save;
1237 
1238 	stv_save = Seismic_tremor_volume;
1239 	Seismic_tremor_magnitude = 0;
1240 	Seismic_tremor_volume = 0;
1241 
1242 	rock_the_mine_frame();
1243 	seismic_disturbance_frame();
1244 
1245 	if (stv_save != 0) {
1246 		if (Seismic_tremor_volume == 0) {
1247 			digi_stop_looping_sound();
1248 			Seismic_sound_playing = 0;
1249 		}
1250 
1251 		if ((GameTime > Next_seismic_sound_time) && Seismic_tremor_volume) {
1252 			int	volume;
1253 
1254 			volume = Seismic_tremor_volume * 2048;
1255 			if (volume > F1_0)
1256 				volume = F1_0;
1257 			digi_change_looping_volume(volume);
1258 			Next_seismic_sound_time = GameTime + d_rand()/4 + 8192;
1259 		}
1260 	}
1261 
1262 }
1263 
1264 int tactile_fire_duration[]={120,80,150,250,150,200,100,180,280,100};
1265 int tactile_fire_repeat[]={260,90,160,160,160,210,110,191,291,111};
1266 
tactile_set_button_jolt()1267 void tactile_set_button_jolt ()
1268  {
1269   #ifdef TACTILE
1270 
1271   FILE *infile;
1272   int t,i;
1273   static int stickmag=-1;
1274   int dur,rep;
1275 
1276   dur=tactile_fire_duration[Primary_weapon];
1277   rep=tactile_fire_repeat[Primary_weapon];
1278 
1279   if (TactileStick)
1280    {
1281   	 if (stickmag==-1)
1282 	  {
1283 	   if (t=FindArg("-stickmag"))
1284 	 		stickmag=atoi (Args[t+1]);
1285 	   else
1286 	   	stickmag=50;
1287 
1288       infile=(FILE *)fopen ("stick.val","rt");
1289 		if (infile!=NULL)
1290 		 {
1291 			for (i=0;i<10;i++)
1292 			 {
1293 			  fscanf (infile,"%d %d\n",&tactile_fire_duration[i],&tactile_fire_repeat[i]);
1294 			  mprintf ((0,"scan value[%d]=%d\n",i,tactile_fire_duration[i]));
1295 			 }
1296 	 		fclose (infile);
1297 		 }
1298 	  }
1299     ButtonReflexJolt (0,stickmag,0,dur,rep);
1300    }
1301   #endif
1302  }
1303 
1304 /*
1305  * reads n weapon_info structs from a CFILE
1306  */
weapon_info_read_n(weapon_info * wi,int n,CFILE * fp,int file_version)1307 extern int weapon_info_read_n(weapon_info *wi, int n, CFILE *fp, int file_version)
1308 {
1309 	int i, j;
1310 
1311 	for (i = 0; i < n; i++) {
1312 		wi[i].render_type = cfile_read_byte(fp);
1313 		wi[i].persistent = cfile_read_byte(fp);
1314 		wi[i].model_num = cfile_read_short(fp);
1315 		wi[i].model_num_inner = cfile_read_short(fp);
1316 
1317 		wi[i].flash_vclip = cfile_read_byte(fp);
1318 		wi[i].robot_hit_vclip = cfile_read_byte(fp);
1319 		wi[i].flash_sound = cfile_read_short(fp);
1320 
1321 		wi[i].wall_hit_vclip = cfile_read_byte(fp);
1322 		wi[i].fire_count = cfile_read_byte(fp);
1323 		wi[i].robot_hit_sound = cfile_read_short(fp);
1324 
1325 		wi[i].ammo_usage = cfile_read_byte(fp);
1326 		wi[i].weapon_vclip = cfile_read_byte(fp);
1327 		wi[i].wall_hit_sound = cfile_read_short(fp);
1328 
1329 		wi[i].destroyable = cfile_read_byte(fp);
1330 		wi[i].matter = cfile_read_byte(fp);
1331 		wi[i].bounce = cfile_read_byte(fp);
1332 		wi[i].homing_flag = cfile_read_byte(fp);
1333 
1334 		wi[i].speedvar = cfile_read_byte(fp);
1335 		wi[i].flags = cfile_read_byte(fp);
1336 		wi[i].flash = cfile_read_byte(fp);
1337 		wi[i].afterburner_size = cfile_read_byte(fp);
1338 
1339 		if (file_version >= 3)
1340 			wi[i].children = cfile_read_byte(fp);
1341 		else
1342 			wi[i].children = -1;
1343 
1344 		wi[i].energy_usage = cfile_read_fix(fp);
1345 		wi[i].fire_wait = cfile_read_fix(fp);
1346 
1347 		if (file_version >= 3)
1348 			wi[i].multi_damage_scale = cfile_read_fix(fp);
1349 		else
1350 			wi[i].multi_damage_scale = F1_0;
1351 
1352 		bitmap_index_read(&wi[i].bitmap, fp);
1353 
1354 		wi[i].blob_size = cfile_read_fix(fp);
1355 		wi[i].flash_size = cfile_read_fix(fp);
1356 		wi[i].impact_size = cfile_read_fix(fp);
1357 		for (j = 0; j < NDL; j++)
1358 			wi[i].strength[j] = cfile_read_fix(fp);
1359 		for (j = 0; j < NDL; j++)
1360 			wi[i].speed[j] = cfile_read_fix(fp);
1361 		wi[i].mass = cfile_read_fix(fp);
1362 		wi[i].drag = cfile_read_fix(fp);
1363 		wi[i].thrust = cfile_read_fix(fp);
1364 		wi[i].po_len_to_width_ratio = cfile_read_fix(fp);
1365 		wi[i].light = cfile_read_fix(fp);
1366 		wi[i].lifetime = cfile_read_fix(fp);
1367 		wi[i].damage_radius = cfile_read_fix(fp);
1368 		bitmap_index_read(&wi[i].picture, fp);
1369 		if (file_version >= 3)
1370 			bitmap_index_read(&wi[i].hires_picture, fp);
1371 		else
1372 			wi[i].hires_picture.index = wi[i].picture.index;
1373 	}
1374 	return i;
1375 }
1376