1 /* $Id: weapon.c,v 1.9 2003-10-11 09:28:38 btb Exp $ */
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.
17 * Functions for weapons...
20 * Revision 1.2 1995/10/31 10:17:39 allender
23 * Revision 1.1 1995/05/16 15:32:16 allender
26 * Revision 2.1 1995/03/21 14:38:43 john
27 * Ifdef'd out the NETWORK code.
29 * Revision 2.0 1995/02/27 11:27:25 john
30 * New version 2.0, which has no anonymous unions, builds with
31 * Watcom 10.0, and doesn't require parsing BITMAPS.TBL.
33 * Revision 1.54 1995/02/15 15:21:48 mike
34 * make smart missile select if mega missiles used up.
37 * Revision 1.53 1995/02/12 02:12:30 john
38 * Fixed bug with state restore making weapon beeps.
40 * Revision 1.52 1995/02/09 20:42:15 mike
41 * change weapon autoselect, always autoselect smart, mega.
43 * Revision 1.51 1995/02/07 20:44:26 mike
44 * autoselect mega, smart when you pick them up.
46 * Revision 1.50 1995/02/07 13:32:25 rob
47 * Added include of multi.h
49 * Revision 1.49 1995/02/07 13:21:33 yuan
52 * Revision 1.48 1995/02/07 13:16:39 yuan
55 * Revision 1.47 1995/02/07 12:53:12 rob
56 * Added network sound prop. to weapon switch.
58 * Revision 1.46 1995/02/06 15:53:17 mike
59 * don't autoselect smart or mega missile when you pick it up.
61 * Revision 1.45 1995/02/02 21:43:34 mike
62 * make autoselection better.
64 * Revision 1.44 1995/02/02 16:27:21 mike
65 * make concussion missiles trade up.
67 * Revision 1.43 1995/02/01 23:34:57 adam
68 * messed with weapon change sounds
70 * Revision 1.42 1995/02/01 17:12:47 mike
71 * Make smart missile, mega missile not auto-select.
73 * Revision 1.41 1995/02/01 15:50:54 mike
74 * fix bogus weapon selection sound code.
76 * Revision 1.40 1995/01/31 16:16:31 mike
77 * Separate smart blobs for robot and player.
79 * Revision 1.39 1995/01/30 21:12:11 mike
80 * Use new weapon selection sounds, different for primary and secondary.
82 * Revision 1.38 1995/01/29 13:46:52 mike
83 * Don't auto-select fusion cannon when you run out of energy.
85 * Revision 1.37 1995/01/20 11:11:13 allender
86 * record weapon changes again. (John somehow lost my 1.35 changes).
88 * Revision 1.36 1995/01/19 17:00:46 john
89 * Made save game work between levels.
91 * Revision 1.34 1995/01/09 17:03:48 mike
92 * fix autoselection of weapons.
94 * Revision 1.33 1995/01/05 15:46:31 john
95 * Made weapons not rearm when starting a saved game.
97 * Revision 1.32 1995/01/03 12:34:23 mike
98 * autoselect next lower weapon if run out of smart or mega missile.
100 * Revision 1.31 1994/12/12 21:39:37 matt
101 * Changed vulcan ammo: 10K max, 5K w/weapon, 1250 per powerup
103 * Revision 1.30 1994/12/09 19:55:04 matt
104 * Added weapon name in "not available in shareware" message
106 * Revision 1.29 1994/12/06 13:50:24 adam
107 * added shareware msg. when choosing 4 top weapons
109 * Revision 1.28 1994/12/02 22:07:13 mike
110 * if you gots 19 concussion missiles and you runs over 4, say you picks up 1, not 4, we do the math, see?
112 * Revision 1.27 1994/12/02 20:06:24 matt
113 * Made vulcan ammo print at approx 25 times actual
115 * Revision 1.26 1994/12/02 15:05:03 matt
116 * Fixed bogus weapon constants and arrays
118 * Revision 1.25 1994/12/02 10:50:34 yuan
121 * Revision 1.24 1994/11/29 15:48:28 matt
122 * selecting weapon now makes sound
124 * Revision 1.23 1994/11/28 11:26:58 matt
125 * Cleaned up hud message printing for picking up weapons
127 * Revision 1.22 1994/11/27 23:13:39 matt
128 * Made changes for new mprintf calling convention
130 * Revision 1.21 1994/11/12 16:38:34 mike
131 * clean up default ammo stuff.
133 * Revision 1.20 1994/11/07 17:41:18 mike
134 * messages for when you try to fire a weapon you don't have or don't have ammo for.
136 * Revision 1.19 1994/10/21 20:40:05 mike
137 * fix double vulcan ammo.
139 * Revision 1.18 1994/10/20 09:49:05 mike
140 * kill messages no one liked...*sniff* *sniff*
142 * Revision 1.17 1994/10/19 11:17:07 mike
143 * Limit amount of player ammo.
145 * Revision 1.16 1994/10/12 08:04:18 mike
146 * Fix proximity/homing confusion.
148 * Revision 1.15 1994/10/11 18:27:58 matt
149 * Changed auto selection of secondary weapons
151 * Revision 1.14 1994/10/08 23:37:54 matt
152 * Don't pick up weapons you already have; also fixed auto_select bug
153 * for seconary weapons
155 * Revision 1.13 1994/10/08 14:55:47 matt
156 * Fixed bug that selected vulcan cannon when picked up ammo, even though
157 * you didn't have the weapon.
159 * Revision 1.12 1994/10/08 12:50:32 matt
160 * Fixed bug that let you select weapons you don't have
162 * Revision 1.11 1994/10/07 23:37:56 matt
163 * Made weapons select when pick up better one
165 * Revision 1.10 1994/10/07 16:02:08 matt
166 * Fixed problem with weapon auto-select
168 * Revision 1.9 1994/10/05 17:00:20 matt
169 * Made player_has_weapon() public and moved constants to header file
171 * Revision 1.8 1994/09/26 11:27:13 mike
172 * Fix auto selection of weapon when you run out of ammo.
174 * Revision 1.7 1994/09/13 16:40:45 mike
175 * Add rearm delay and missile firing delay.
177 * Revision 1.6 1994/09/13 14:43:12 matt
178 * Added cockpit weapon displays
180 * Revision 1.5 1994/09/03 15:23:06 mike
181 * Auto select next weaker weapon when one runs out, clean up code.
183 * Revision 1.4 1994/09/02 16:38:19 mike
184 * Eliminate a pile of arrays, associate weapon data with Weapon_info.
186 * Revision 1.3 1994/09/02 11:57:10 mike
187 * Add a bunch of stuff, I forget what.
189 * Revision 1.2 1994/06/03 16:26:32 john
192 * Revision 1.1 1994/06/03 14:40:43 john
203 static char rcsid[] = "$Id: weapon.c,v 1.9 2003-10-11 09:28:38 btb Exp $";
220 #include "fireball.h"
227 #if defined (TACTILE)
231 int POrderList (int num);
232 int SOrderList (int num);
233 // Note, only Vulcan cannon requires ammo.
234 // NOTE: Now Vulcan and Gauss require ammo. -5/3/95 Yuan
235 //ubyte Default_primary_ammo_level[MAX_PRIMARY_WEAPONS] = {255, 0, 255, 255, 255};
236 //ubyte Default_secondary_ammo_level[MAX_SECONDARY_WEAPONS] = {3, 0, 0, 0, 0};
238 // Convert primary weapons to indices in Weapon_info array.
239 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};
240 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};
242 //for each Secondary weapon, which gun it fires out of
243 ubyte Secondary_weapon_to_gun_num[MAX_SECONDARY_WEAPONS] = {4,4,7,7,7,4,4,7,4,7};
245 int Primary_ammo_max[MAX_PRIMARY_WEAPONS] = {0, VULCAN_AMMO_MAX, 0, 0, 0, 0, VULCAN_AMMO_MAX, 0, 0, 0};
246 ubyte Secondary_ammo_max[MAX_SECONDARY_WEAPONS] = {20, 10, 10, 5, 5, 20, 20, 15, 10, 10};
248 //for each primary weapon, what kind of powerup gives weapon
249 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};
251 //for each Secondary weapon, what kind of powerup gives weapon
252 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};
254 weapon_info Weapon_info[MAX_WEAPON_TYPES];
255 int N_weapon_types=0;
256 sbyte Primary_weapon, Secondary_weapon;
258 // autoselect ordering
260 ubyte PrimaryOrder[]={9,8,7,6,5,4,3,2,1,0,255};
261 ubyte SecondaryOrder[]={9,8,4,3,1,5,0,255,7,6,2};
263 ubyte DefaultPrimaryOrder[]={9,8,7,6,5,4,3,2,1,0,255};
264 ubyte DefaultSecondaryOrder[]={9,8,4,3,1,5,0,255,7,6,2};
266 // Cycling weapon key pressed?
270 //allow player to reorder menus?
271 extern ubyte MenuReordering;
273 //char *Primary_weapon_names[MAX_PRIMARY_WEAPONS] = {
276 // "Spreadfire Cannon",
281 //char *Secondary_weapon_names[MAX_SECONDARY_WEAPONS] = {
282 // "Concussion Missile",
289 //char *Primary_weapon_names_short[MAX_PRIMARY_WEAPONS] = {
297 //char *Secondary_weapon_names_short[MAX_SECONDARY_WEAPONS] = {
298 // "Concsn\nMissile",
299 // "Homing\nMissile",
305 sbyte Weapon_is_energy[MAX_WEAPON_TYPES] = {
316 // ; (0) Laser Level 1
317 // ; (1) Laser Level 2
318 // ; (2) Laser Level 3
319 // ; (3) Laser Level 4
324 // ; (8) ---------- Concussion Missile ----------
325 // ; (9) ---------- Flare ----------
326 // ; (10) ---------- Blue laser that blue guy shoots -----------
327 // ; (11) ---------- Vulcan Cannon ----------
328 // ; (12) ---------- Spreadfire Cannon ----------
329 // ; (13) ---------- Plasma Cannon ----------
330 // ; (14) ---------- Fusion Cannon ----------
331 // ; (15) ---------- Homing Missile ----------
332 // ; (16) ---------- Proximity Bomb ----------
333 // ; (17) ---------- Smart Missile ----------
334 // ; (18) ---------- Mega Missile ----------
335 // ; (19) ---------- Children of the PLAYER'S Smart Missile ----------
336 // ; (20) ---------- Bad Guy Spreadfire Laser ----------
337 // ; (21) ---------- SuperMech Homing Missile ----------
338 // ; (22) ---------- Regular Mech's missile -----------
339 // ; (23) ---------- Silent Spreadfire Laser ----------
340 // ; (24) ---------- Red laser that baby spiders shoot -----------
341 // ; (25) ---------- Green laser that rifleman shoots -----------
342 // ; (26) ---------- Plasma gun that 'plasguy' fires ------------
343 // ; (27) ---------- Blobs fired by Red Spiders -----------
344 // ; (28) ---------- Final Boss's Mega Missile ----------
345 // ; (29) ---------- Children of the ROBOT'S Smart Missile ----------
346 // ; (30) Laser Level 5
347 // ; (31) Laser Level 6
348 // ; (32) ---------- Super Vulcan Cannon ----------
349 // ; (33) ---------- Super Spreadfire Cannon ----------
350 // ; (34) ---------- Super Plasma Cannon ----------
351 // ; (35) ---------- Super Fusion Cannon ----------
353 // ------------------------------------------------------------------------------------
359 // See weapon.h for bit values
360 int player_has_weapon(int weapon_num, int secondary_flag)
362 int return_value = 0;
365 // Hack! If energy goes negative, you can't fire a weapon that doesn't require energy.
366 // But energy should not go negative (but it does), so find out why it does!
367 if (Players[Player_num].energy < 0)
368 Players[Player_num].energy = 0;
370 if (!secondary_flag) {
371 weapon_index = Primary_weapon_to_weapon_info[weapon_num];
373 if (Players[Player_num].primary_weapon_flags & (1 << weapon_num))
374 return_value |= HAS_WEAPON_FLAG;
376 // Special case: Gauss cannon uses vulcan ammo.
377 if (weapon_num == GAUSS_INDEX) {
378 if (Weapon_info[weapon_index].ammo_usage <= Players[Player_num].primary_ammo[VULCAN_INDEX])
379 return_value |= HAS_AMMO_FLAG;
381 if (Weapon_info[weapon_index].ammo_usage <= Players[Player_num].primary_ammo[weapon_num])
382 return_value |= HAS_AMMO_FLAG;
384 if (weapon_num == OMEGA_INDEX) { // Hack: Make sure player has energy to omega
385 if (Players[Player_num].energy || Omega_charge)
386 return_value |= HAS_ENERGY_FLAG;
388 if (Weapon_info[weapon_index].energy_usage <= Players[Player_num].energy)
389 return_value |= HAS_ENERGY_FLAG;
392 weapon_index = Secondary_weapon_to_weapon_info[weapon_num];
394 if (Players[Player_num].secondary_weapon_flags & (1 << weapon_num))
395 return_value |= HAS_WEAPON_FLAG;
397 if (Weapon_info[weapon_index].ammo_usage <= Players[Player_num].secondary_ammo[weapon_num])
398 return_value |= HAS_AMMO_FLAG;
400 if (Weapon_info[weapon_index].energy_usage <= Players[Player_num].energy)
401 return_value |= HAS_ENERGY_FLAG;
407 void InitWeaponOrdering ()
409 // short routine to setup default weapon priorities for new pilots
413 for (i=0;i<MAX_PRIMARY_WEAPONS+1;i++)
414 PrimaryOrder[i]=DefaultPrimaryOrder[i];
415 for (i=0;i<MAX_SECONDARY_WEAPONS+1;i++)
416 SecondaryOrder[i]=DefaultSecondaryOrder[i];
421 mprintf ((0,"Cycling primary!\n"));
423 auto_select_weapon (0);
427 void CycleSecondary ()
429 mprintf ((0,"Cycling secondary!\n"));
431 auto_select_weapon (1);
436 // ------------------------------------------------------------------------------------
437 //if message flag set, print message saying selected
438 void select_weapon(int weapon_num, int secondary_flag, int print_message, int wait_for_rearm)
442 if (Newdemo_state==ND_STATE_RECORDING )
443 newdemo_record_player_weapon(secondary_flag, weapon_num);
445 if (!secondary_flag) {
446 if (Primary_weapon != weapon_num) {
447 if (wait_for_rearm) digi_play_sample_once( SOUND_GOOD_SELECTION_PRIMARY, F1_0 );
449 if (Game_mode & GM_MULTI) {
450 if (wait_for_rearm) multi_send_play_sound(SOUND_GOOD_SELECTION_PRIMARY, F1_0);
454 Next_laser_fire_time = GameTime + REARM_TIME;
456 Next_laser_fire_time = 0;
457 Global_laser_firing_count = 0;
459 // Select super version if available.
463 ; // -- MK, only plays when can't fire weapon anyway, fixes bug -- digi_play_sample_once( SOUND_ALREADY_SELECTED, F1_0 );
465 digi_play_sample_once( SOUND_BAD_SELECTION, F1_0 );
468 Primary_weapon = weapon_num;
469 weapon_name = PRIMARY_WEAPON_NAMES(weapon_num);
470 #if defined (TACTILE)
471 tactile_set_button_jolt();
475 //save flag for whether was super version
476 Primary_last_was_super[weapon_num % SUPER_WEAPON] = (weapon_num >= SUPER_WEAPON);
480 if (Secondary_weapon != weapon_num) {
481 if (wait_for_rearm) digi_play_sample_once( SOUND_GOOD_SELECTION_SECONDARY, F1_0 );
483 if (Game_mode & GM_MULTI) {
484 if (wait_for_rearm) multi_send_play_sound(SOUND_GOOD_SELECTION_PRIMARY, F1_0);
488 Next_missile_fire_time = GameTime + REARM_TIME;
490 Next_missile_fire_time = 0;
491 Global_missile_firing_count = 0;
496 digi_play_sample_once( SOUND_ALREADY_SELECTED, F1_0 );
498 digi_play_sample_once( SOUND_BAD_SELECTION, F1_0 );
502 Secondary_weapon = weapon_num;
503 weapon_name = SECONDARY_WEAPON_NAMES(weapon_num);
505 //save flag for whether was super version
506 Secondary_last_was_super[weapon_num % SUPER_WEAPON] = (weapon_num >= SUPER_WEAPON);
511 if (weapon_num == LASER_INDEX && !secondary_flag)
512 HUD_init_message("%s Level %d %s", weapon_name, Players[Player_num].laser_level+1, TXT_SELECTED);
514 HUD_init_message("%s %s", weapon_name, TXT_SELECTED);
519 //flags whether the last time we use this weapon, it was the 'super' version
520 ubyte Primary_last_was_super[MAX_PRIMARY_WEAPONS];
521 ubyte Secondary_last_was_super[MAX_SECONDARY_WEAPONS];
523 // ------------------------------------------------------------------------------------
524 // Select a weapon, primary or secondary.
525 void do_weapon_select(int weapon_num, int secondary_flag)
527 int weapon_num_save=weapon_num;
528 int weapon_status,current,has_flag;
529 ubyte last_was_super;
531 if (!secondary_flag) {
532 current = Primary_weapon;
533 last_was_super = Primary_last_was_super[weapon_num];
534 has_flag = HAS_WEAPON_FLAG;
537 current = Secondary_weapon;
538 last_was_super = Secondary_last_was_super[weapon_num];
539 has_flag = HAS_WEAPON_FLAG+HAS_AMMO_FLAG;
542 if (current == weapon_num || current == weapon_num+SUPER_WEAPON) {
544 //already have this selected, so toggle to other of normal/super version
546 weapon_num += weapon_num+SUPER_WEAPON - current;
547 weapon_status = player_has_weapon(weapon_num, secondary_flag);
551 //go to last-select version of requested missile
554 weapon_num += SUPER_WEAPON;
556 weapon_status = player_has_weapon(weapon_num, secondary_flag);
558 //if don't have last-selected, try other version
560 if ((weapon_status & has_flag) != has_flag) {
561 weapon_num = 2*weapon_num_save+SUPER_WEAPON - weapon_num;
562 weapon_status = player_has_weapon(weapon_num, secondary_flag);
563 if ((weapon_status & has_flag) != has_flag)
564 weapon_num = 2*weapon_num_save+SUPER_WEAPON - weapon_num;
568 //if we don't have the weapon we're switching to, give error & bail
569 if ((weapon_status & has_flag) != has_flag) {
570 if (!secondary_flag) {
571 if (weapon_num==SUPER_LASER_INDEX)
572 return; //no such thing as super laser, so no error
573 HUD_init_message("%s %s!", TXT_DONT_HAVE, PRIMARY_WEAPON_NAMES(weapon_num));
576 HUD_init_message("%s %s%s",TXT_HAVE_NO, SECONDARY_WEAPON_NAMES(weapon_num), TXT_SX);
577 digi_play_sample( SOUND_BAD_SELECTION, F1_0 );
581 //now actually select the weapon
582 select_weapon(weapon_num, secondary_flag, 1, 1);
585 // ----------------------------------------------------------------------------------------
586 // Automatically select next best weapon if unable to fire current weapon.
587 // Weapon type: 0==primary, 1==secondary
588 void auto_select_weapon(int weapon_type)
594 if (weapon_type==0) {
595 r = player_has_weapon(Primary_weapon, 0);
596 if (r != HAS_ALL || Cycling) {
600 cur_weapon = POrderList(Primary_weapon);
601 cutpoint = POrderList (255);
606 if (cur_weapon>=cutpoint)
612 HUD_init_message(TXT_NO_PRIMARY);
615 ButtonReflexClear(0);
617 select_weapon(0, 0, 0, 1);
620 select_weapon (Primary_weapon,0,0,1);
630 if (cur_weapon==MAX_PRIMARY_WEAPONS)
633 // Hack alert! Because the fusion uses 0 energy at the end (it's got the weird chargeup)
634 // it looks like it takes 0 to fire, but it doesn't, so never auto-select.
635 // if (PrimaryOrder[cur_weapon] == FUSION_INDEX)
638 if (PrimaryOrder[cur_weapon] == Primary_weapon) {
641 HUD_init_message(TXT_NO_PRIMARY);
644 ButtonReflexClear(0);
647 // if (POrderList(0)<POrderList(255))
648 select_weapon(0, 0, 0, 1);
651 select_weapon (Primary_weapon,0,0,1);
653 try_again = 0; // Tried all weapons!
655 } else if (PrimaryOrder[cur_weapon]!=255 && player_has_weapon(PrimaryOrder[cur_weapon], 0) == HAS_ALL) {
656 select_weapon(PrimaryOrder[cur_weapon], 0, 1, 1 );
664 Assert(weapon_type==1);
665 r = player_has_weapon(Secondary_weapon, 1);
666 if (r != HAS_ALL || Cycling) {
670 cur_weapon = SOrderList(Secondary_weapon);
671 cutpoint = SOrderList (255);
677 if (cur_weapon>=cutpoint)
682 HUD_init_message("No secondary weapons selected!");
684 select_weapon (Secondary_weapon,1,0,1);
692 if (cur_weapon==MAX_SECONDARY_WEAPONS)
695 if (SecondaryOrder[cur_weapon] == Secondary_weapon) {
697 HUD_init_message("No secondary weapons available!");
699 select_weapon (Secondary_weapon,1,0,1);
701 try_again = 0; // Tried all weapons!
702 } else if (player_has_weapon(SecondaryOrder[cur_weapon], 1) == HAS_ALL) {
703 select_weapon(SecondaryOrder[cur_weapon], 1, 1, 1 );
716 // ----------------------------------------------------------------------------------------
717 // Show player which weapons he has, how much ammo...
718 // Looks like a debug screen now because it writes to mono screen, but that will change...
719 void show_weapon_status(void)
723 for (i=0; i<MAX_PRIMARY_WEAPONS; i++) {
724 if (Players[Player_num].primary_weapon_flags & (1 << i))
725 mprintf((0, "HAVE"));
729 mprintf((0, " Weapon: %20s, charges: %4i\n", PRIMARY_WEAPON_NAMES(i), Players[Player_num].primary_ammo[i]));
733 for (i=0; i<MAX_SECONDARY_WEAPONS; i++) {
734 if (Players[Player_num].secondary_weapon_flags & (1 << i))
735 mprintf((0, "HAVE"));
739 mprintf((0, " Weapon: %20s, charges: %4i\n", SECONDARY_WEAPON_NAMES(i), Players[Player_num].secondary_ammo[i]));
749 // ---------------------------------------------------------------------
750 //called when one of these weapons is picked up
751 //when you pick up a secondary, you always get the weapon & ammo for it
752 // Returns true if powerup picked up, else returns false.
753 int pick_up_secondary(int weapon_index,int count)
759 max = Secondary_ammo_max[weapon_index];
761 if (Players[Player_num].flags & PLAYER_FLAGS_AMMO_RACK)
764 if (Players[Player_num].secondary_ammo[weapon_index] >= max) {
765 HUD_init_message("%s %i %ss!", TXT_ALREADY_HAVE, Players[Player_num].secondary_ammo[weapon_index],SECONDARY_WEAPON_NAMES(weapon_index));
769 Players[Player_num].secondary_weapon_flags |= (1<<weapon_index);
770 Players[Player_num].secondary_ammo[weapon_index] += count;
772 num_picked_up = count;
773 if (Players[Player_num].secondary_ammo[weapon_index] > max) {
774 num_picked_up = count - (Players[Player_num].secondary_ammo[weapon_index] - max);
775 Players[Player_num].secondary_ammo[weapon_index] = max;
778 cutpoint=SOrderList (255);
779 if (SOrderList (weapon_index)<cutpoint && ((SOrderList (weapon_index) < SOrderList(Secondary_weapon)) || (Players[Player_num].secondary_ammo[Secondary_weapon] == 0)) )
780 select_weapon(weapon_index,1, 0, 1);
782 //if we don't auto-select this weapon, but it's a proxbomb or smart mine,
783 //we want to do a mini-auto-selection that applies to the drop bomb key
785 if ((weapon_index == PROXIMITY_INDEX || weapon_index == SMART_MINE_INDEX) &&
786 !(Secondary_weapon == PROXIMITY_INDEX || Secondary_weapon == SMART_MINE_INDEX)) {
789 cur = Secondary_last_was_super[PROXIMITY_INDEX]?SMART_MINE_INDEX:PROXIMITY_INDEX;
791 if (SOrderList (weapon_index) < SOrderList(cur))
792 Secondary_last_was_super[PROXIMITY_INDEX] = (weapon_index == SMART_MINE_INDEX);
796 //note: flash for all but concussion was 7,14,21
798 PALETTE_FLASH_ADD(15,15,15);
799 HUD_init_message("%d %s%s",num_picked_up,SECONDARY_WEAPON_NAMES(weapon_index), TXT_SX);
802 PALETTE_FLASH_ADD(10,10,10);
803 HUD_init_message("%s!",SECONDARY_WEAPON_NAMES(weapon_index));
809 void ReorderPrimary ()
811 newmenu_item m[MAX_PRIMARY_WEAPONS+1];
814 for (i=0;i<MAX_PRIMARY_WEAPONS+1;i++)
816 m[i].type=NM_TYPE_MENU;
817 if (PrimaryOrder[i]==255)
818 m[i].text="
\88\88\88\88\88\88\88 Never autoselect
\88\88\88\88\88\88\88";
820 m[i].text=(char *)PRIMARY_WEAPON_NAMES(PrimaryOrder[i]);
821 m[i].value=PrimaryOrder[i];
824 i = newmenu_do("Reorder Primary","Shift+Up/Down arrow to move item", i, m, NULL);
827 for (i=0;i<MAX_PRIMARY_WEAPONS+1;i++)
828 PrimaryOrder[i]=m[i].value;
831 void ReorderSecondary ()
833 newmenu_item m[MAX_SECONDARY_WEAPONS+1];
836 for (i=0;i<MAX_SECONDARY_WEAPONS+1;i++)
838 m[i].type=NM_TYPE_MENU;
839 if (SecondaryOrder[i]==255)
840 m[i].text="
\88\88\88\88\88\88\88 Never autoselect
\88\88\88\88\88\88\88";
842 m[i].text=(char *)SECONDARY_WEAPON_NAMES(SecondaryOrder[i]);
843 m[i].value=SecondaryOrder[i];
846 i = newmenu_do("Reorder Secondary","Shift+Up/Down arrow to move item", i, m, NULL);
848 for (i=0;i<MAX_SECONDARY_WEAPONS+1;i++)
849 SecondaryOrder[i]=m[i].value;
852 int POrderList (int num)
856 for (i=0;i<MAX_PRIMARY_WEAPONS+1;i++)
857 if (PrimaryOrder[i]==num)
859 mprintf ((0,"Primary %d has priority of %d!\n",num,i));
862 Error ("Primary Weapon is not in order list!!!");
865 int SOrderList (int num)
869 for (i=0;i<MAX_SECONDARY_WEAPONS+1;i++)
870 if (SecondaryOrder[i]==num)
872 mprintf ((0,"Secondary %d has priority of %d!\n",num,i));
875 mprintf ((0,"Error! Secondary Num=%d\n",num));
876 Error ("Secondary Weapon is not in order list!!!");
880 //called when a primary weapon is picked up
881 //returns true if actually picked up
882 int pick_up_primary(int weapon_index)
884 //ushort old_flags = Players[Player_num].primary_weapon_flags;
885 ushort flag = 1<<weapon_index;
887 int supposed_weapon=Primary_weapon;
889 if (weapon_index!=LASER_INDEX && Players[Player_num].primary_weapon_flags & flag) { //already have
890 HUD_init_message("%s %s!", TXT_ALREADY_HAVE_THE, PRIMARY_WEAPON_NAMES(weapon_index));
894 Players[Player_num].primary_weapon_flags |= flag;
896 cutpoint=POrderList (255);
898 if (Primary_weapon==LASER_INDEX && Players[Player_num].laser_level>=4)
899 supposed_weapon=SUPER_LASER_INDEX; // allotment for stupid way of doing super laser
902 if (POrderList(weapon_index)<cutpoint && POrderList(weapon_index)<POrderList(supposed_weapon))
903 select_weapon(weapon_index,0,0,1);
905 PALETTE_FLASH_ADD(7,14,21);
906 mprintf ((0,"Weapon index: %d\n",weapon_index));
908 if (weapon_index!=LASER_INDEX)
909 HUD_init_message("%s!",PRIMARY_WEAPON_NAMES(weapon_index));
913 int check_to_use_primary(int weapon_index)
915 ushort old_flags = Players[Player_num].primary_weapon_flags;
916 ushort flag = 1<<weapon_index;
919 cutpoint=POrderList (255);
921 if (!(old_flags & flag) && POrderList(weapon_index)<cutpoint && POrderList(weapon_index)<POrderList(Primary_weapon))
923 if (weapon_index==SUPER_LASER_INDEX)
924 select_weapon(LASER_INDEX,0,0,1);
926 select_weapon(weapon_index,0,0,1);
929 PALETTE_FLASH_ADD(7,14,21);
936 //called when ammo (for the vulcan cannon) is picked up
937 // Returns the amount picked up
938 int pick_up_ammo(int class_flag,int weapon_index,int ammo_count)
940 int max,cutpoint,supposed_weapon=Primary_weapon;
941 int old_ammo=class_flag; //kill warning
943 Assert(class_flag==CLASS_PRIMARY && weapon_index==VULCAN_INDEX);
945 max = Primary_ammo_max[weapon_index];
946 if (Players[Player_num].flags & PLAYER_FLAGS_AMMO_RACK)
949 if (Players[Player_num].primary_ammo[weapon_index] == max)
952 old_ammo = Players[Player_num].primary_ammo[weapon_index];
954 Players[Player_num].primary_ammo[weapon_index] += ammo_count;
956 if (Players[Player_num].primary_ammo[weapon_index] > max) {
957 ammo_count += (max - Players[Player_num].primary_ammo[weapon_index]);
958 Players[Player_num].primary_ammo[weapon_index] = max;
960 cutpoint=POrderList (255);
962 if (Primary_weapon==LASER_INDEX && Players[Player_num].laser_level>=4)
963 supposed_weapon=SUPER_LASER_INDEX; // allotment for stupid way of doing super laser
966 if (Players[Player_num].primary_weapon_flags&(1<<weapon_index) && weapon_index>Primary_weapon && old_ammo==0 &&
967 POrderList(weapon_index)<cutpoint && POrderList(weapon_index)<POrderList(supposed_weapon))
968 select_weapon(weapon_index,0,0,1);
970 return ammo_count; //return amount used
973 #define SMEGA_SHAKE_TIME (F1_0*2)
974 #define MAX_SMEGA_DETONATES 4
975 fix Smega_detonate_times[MAX_SMEGA_DETONATES];
977 // Call this to initialize for a new level.
978 // Sets all super mega missile detonation times to 0 which means there aren't any.
979 void init_smega_detonates(void)
983 for (i=0; i<MAX_SMEGA_DETONATES; i++)
984 Smega_detonate_times[i] = 0;
987 fix Seismic_tremor_magnitude;
988 fix Next_seismic_sound_time;
989 int Seismic_sound_playing = 0;
990 int Seismic_tremor_volume;
992 int Seismic_sound = SOUND_SEISMIC_DISTURBANCE_START;
994 // If a smega missile been detonated, rock the mine!
995 // This should be called every frame.
996 // Maybe this should affect all robots, being called when they get their physics done.
997 void rock_the_mine_frame(void)
1001 for (i=0; i<MAX_SMEGA_DETONATES; i++) {
1003 if (Smega_detonate_times[i] != 0) {
1005 delta_time = GameTime - Smega_detonate_times[i];
1007 if (!Seismic_sound_playing) {
1008 digi_play_sample_looping(Seismic_sound, F1_0, -1, -1);
1009 Seismic_sound_playing = 1;
1010 Next_seismic_sound_time = GameTime + d_rand()/2;
1013 if (delta_time < SMEGA_SHAKE_TIME) {
1015 // Control center destroyed, rock the player's ship.
1017 // -- fc = abs(delta_time - SMEGA_SHAKE_TIME/2);
1018 // Changed 10/23/95 to make decreasing for super mega missile.
1019 fc = (SMEGA_SHAKE_TIME - delta_time)/2;
1020 fc /= SMEGA_SHAKE_TIME/32;
1027 Seismic_tremor_volume += fc;
1029 rx = fixmul(d_rand() - 16384, 3*F1_0/16 + (F1_0*(16-fc))/32);
1030 rz = fixmul(d_rand() - 16384, 3*F1_0/16 + (F1_0*(16-fc))/32);
1032 ConsoleObject->mtype.phys_info.rotvel.x += rx;
1033 ConsoleObject->mtype.phys_info.rotvel.z += rz;
1036 if (Buddy_objnum != -1) {
1037 Objects[Buddy_objnum].mtype.phys_info.rotvel.x += rx*4;
1038 Objects[Buddy_objnum].mtype.phys_info.rotvel.z += rz*4;
1041 // Shake a guided missile!
1042 Seismic_tremor_magnitude += rx;
1045 Smega_detonate_times[i] = 0;
1050 // Hook in the rumble sound effect here.
1053 extern int Level_shake_frequency, Level_shake_duration;
1055 extern void multi_send_seismic (fix,fix);
1058 #define SEISMIC_DISTURBANCE_DURATION (F1_0*5)
1059 fix Seismic_disturbance_start_time = 0, Seismic_disturbance_end_time;
1061 int Seismic_level=0;
1063 int on_seismic_level(void)
1065 return Seismic_level;
1068 void init_seismic_disturbances(void)
1070 Seismic_disturbance_start_time = 0;
1071 Seismic_disturbance_end_time = 0;
1074 // Return true if time to start a seismic disturbance.
1075 int start_seismic_disturbance(void)
1079 if (Level_shake_duration < 1)
1082 rval = (2 * fixmul(d_rand(), Level_shake_frequency)) < FrameTime;
1085 Seismic_disturbance_start_time = GameTime;
1086 Seismic_disturbance_end_time = GameTime + Level_shake_duration;
1087 if (!Seismic_sound_playing) {
1088 digi_play_sample_looping(Seismic_sound, F1_0, -1, -1);
1089 Seismic_sound_playing = 1;
1090 Next_seismic_sound_time = GameTime + d_rand()/2;
1094 if (Game_mode & GM_MULTI)
1095 multi_send_seismic (Seismic_disturbance_start_time,Seismic_disturbance_end_time);
1102 void seismic_disturbance_frame(void)
1104 if (Level_shake_frequency) {
1105 if (((Seismic_disturbance_start_time < GameTime) && (Seismic_disturbance_end_time > GameTime)) || start_seismic_disturbance()) {
1109 delta_time = GameTime - Seismic_disturbance_start_time;
1111 fc = abs(delta_time - (Seismic_disturbance_end_time - Seismic_disturbance_start_time)/2);
1119 Seismic_tremor_volume += fc;
1121 rx = fixmul(d_rand() - 16384, 3*F1_0/16 + (F1_0*(16-fc))/32);
1122 rz = fixmul(d_rand() - 16384, 3*F1_0/16 + (F1_0*(16-fc))/32);
1124 ConsoleObject->mtype.phys_info.rotvel.x += rx;
1125 ConsoleObject->mtype.phys_info.rotvel.z += rz;
1128 if (Buddy_objnum != -1) {
1129 Objects[Buddy_objnum].mtype.phys_info.rotvel.x += rx*4;
1130 Objects[Buddy_objnum].mtype.phys_info.rotvel.z += rz*4;
1133 // Shake a guided missile!
1134 Seismic_tremor_magnitude += rx;
1140 // Call this when a smega detonates to start the process of rocking the mine.
1141 void smega_rock_stuff(void)
1145 for (i=0; i<MAX_SMEGA_DETONATES; i++) {
1146 if (Smega_detonate_times[i] + SMEGA_SHAKE_TIME < GameTime)
1147 Smega_detonate_times[i] = 0;
1150 for (i=0; i<MAX_SMEGA_DETONATES; i++) {
1151 if (Smega_detonate_times[i] == 0) {
1152 Smega_detonate_times[i] = GameTime;
1158 int Super_mines_yes = 1;
1160 // Call this once/frame to process all super mines in the level.
1161 void process_super_mines_frame(void)
1166 // If we don't know of there being any super mines in the level, just
1167 // check every 8th object each frame.
1168 if (Super_mines_yes == 0) {
1169 start = FrameCount & 7;
1176 Super_mines_yes = 0;
1178 for (i=start; i<=Highest_object_index; i+=add) {
1179 if ((Objects[i].type == OBJ_WEAPON) && (Objects[i].id == SUPERPROX_ID)) {
1182 parent_num = Objects[i].ctype.laser_info.parent_num;
1184 Super_mines_yes = 1;
1185 if (Objects[i].lifeleft + F1_0*2 < Weapon_info[SUPERPROX_ID].lifetime) {
1186 vms_vector *bombpos;
1188 bombpos = &Objects[i].pos;
1190 for (j=0; j<=Highest_object_index; j++) {
1191 if ((Objects[j].type == OBJ_PLAYER) || (Objects[j].type == OBJ_ROBOT)) {
1194 dist = vm_vec_dist_quick(bombpos, &Objects[j].pos);
1196 if (j != parent_num)
1197 if (dist - Objects[j].size < F1_0*20)
1199 if (Objects[i].segnum == Objects[j].segnum)
1200 Objects[i].lifeleft = 1;
1202 // Object which is close enough to detonate smart mine is not in same segment as smart mine.
1203 // Need to do a more expensive check to make sure there isn't an obstruction.
1204 if (((FrameCount ^ (i+j)) % 4) == 0) {
1209 mprintf((0, "Expensive proxmine collision check. Frame %i\n", FrameCount));
1211 fq.startseg = Objects[i].segnum;
1212 fq.p0 = &Objects[i].pos;
1213 fq.p1 = &Objects[j].pos;
1216 fq.ignore_obj_list = NULL;
1219 fate = find_vector_intersection(&fq, &hit_data);
1220 if (fate != HIT_WALL)
1221 Objects[i].lifeleft = 1;
1233 #define SPIT_SPEED 20
1235 //this function is for when the player intentionally drops a powerup
1236 //this function is based on drop_powerup()
1237 int spit_powerup(object *spitter, int id,int seed)
1241 vms_vector new_velocity, new_pos;
1245 vm_vec_scale_add(&new_velocity,&spitter->mtype.phys_info.velocity,&spitter->orient.fvec,i2f(SPIT_SPEED));
1247 new_velocity.x += (d_rand() - 16384) * SPIT_SPEED * 2;
1248 new_velocity.y += (d_rand() - 16384) * SPIT_SPEED * 2;
1249 new_velocity.z += (d_rand() - 16384) * SPIT_SPEED * 2;
1251 // Give keys zero velocity so they can be tracked better in multi
1253 if ((Game_mode & GM_MULTI) && (id >= POW_KEY_BLUE) && (id <= POW_KEY_GOLD))
1254 vm_vec_zero(&new_velocity);
1256 //there's a piece of code which lets the player pick up a powerup if
1257 //the distance between him and the powerup is less than 2 time their
1258 //combined radii. So we need to create powerups pretty far out from
1261 vm_vec_scale_add(&new_pos,&spitter->pos,&spitter->orient.fvec,spitter->size);
1264 if (Game_mode & GM_MULTI)
1266 if (Net_create_loc >= MAX_NET_CREATE_OBJECTS)
1268 mprintf( (0, "WEAPON:Not enough slots to drop all powerups!\n" ));
1274 objnum = obj_create( OBJ_POWERUP, id, spitter->segnum, &new_pos, &vmd_identity_matrix, Powerup_info[id].size, CT_POWERUP, MT_PHYSICS, RT_POWERUP);
1277 mprintf((1, "Can't create object in object_create_egg. Aborting.\n"));
1282 obj = &Objects[objnum];
1284 obj->mtype.phys_info.velocity = new_velocity;
1285 obj->mtype.phys_info.drag = 512; //1024;
1286 obj->mtype.phys_info.mass = F1_0;
1288 obj->mtype.phys_info.flags = PF_BOUNCE;
1290 obj->rtype.vclip_info.vclip_num = Powerup_info[obj->id].vclip_num;
1291 obj->rtype.vclip_info.frametime = Vclip[obj->rtype.vclip_info.vclip_num].frame_time;
1292 obj->rtype.vclip_info.framenum = 0;
1294 if (spitter == ConsoleObject)
1295 obj->ctype.powerup_info.flags |= PF_SPAT_BY_PLAYER;
1300 case POW_SHIELD_BOOST:
1302 obj->lifeleft = (d_rand() + F1_0*3) * 64; // Lives for 3 to 3.5 binary minutes (a binary minute is 64 seconds)
1303 if (Game_mode & GM_MULTI)
1307 //if (Game_mode & GM_MULTI)
1308 // obj->lifeleft = (d_rand() + F1_0*3) * 64; // Lives for 5 to 5.5 binary minutes (a binary minute is 64 seconds)
1315 void DropCurrentWeapon ()
1317 int objnum,ammo=0,seed;
1319 if (Primary_weapon==0)
1321 HUD_init_message("You cannot drop your base weapon!");
1325 HUD_init_message("%s dropped!",PRIMARY_WEAPON_NAMES(Primary_weapon));
1326 digi_play_sample (SOUND_DROP_WEAPON,F1_0);
1330 objnum = spit_powerup(ConsoleObject,Primary_weapon_to_powerup[Primary_weapon],seed);
1335 if (Primary_weapon == VULCAN_INDEX || Primary_weapon == GAUSS_INDEX) {
1337 //if it's one of these, drop some ammo with the weapon
1339 ammo = Players[Player_num].primary_ammo[VULCAN_INDEX];
1341 if ((Players[Player_num].primary_weapon_flags & HAS_FLAG(VULCAN_INDEX)) && (Players[Player_num].primary_weapon_flags & HAS_FLAG(GAUSS_INDEX)))
1342 ammo /= 2; //if both vulcan & gauss, drop half
1344 Players[Player_num].primary_ammo[VULCAN_INDEX] -= ammo;
1347 Objects[objnum].ctype.powerup_info.count = ammo;
1350 if (Primary_weapon == OMEGA_INDEX) {
1352 //dropped weapon has current energy
1355 Objects[objnum].ctype.powerup_info.count = Omega_charge;
1359 if ((Game_mode & GM_MULTI) && objnum>-1)
1360 multi_send_drop_weapon(objnum,seed);
1363 Players[Player_num].primary_weapon_flags &= (~(1<<Primary_weapon));
1364 auto_select_weapon (0);
1368 void DropSecondaryWeapon ()
1372 if (Players[Player_num].secondary_ammo[Secondary_weapon] ==0)
1374 HUD_init_message("No secondary weapon to drop!");
1378 if ((Secondary_weapon_to_powerup[Secondary_weapon]==POW_PROXIMITY_WEAPON ||
1379 Secondary_weapon_to_powerup[Secondary_weapon]==POW_SMART_MINE) &&
1380 Players[Player_num].secondary_ammo[Secondary_weapon]<4)
1382 HUD_init_message("You need at least 4 to drop!");
1386 HUD_init_message("%s dropped!",SECONDARY_WEAPON_NAMES(Secondary_weapon));
1387 digi_play_sample (SOUND_DROP_WEAPON,F1_0);
1391 objnum = spit_powerup(ConsoleObject,Secondary_weapon_to_powerup[Secondary_weapon],seed);
1398 if ((Game_mode & GM_MULTI) && objnum>-1)
1399 multi_send_drop_weapon(objnum,seed);
1402 if (Secondary_weapon_to_powerup[Secondary_weapon]==POW_PROXIMITY_WEAPON ||
1403 Secondary_weapon_to_powerup[Secondary_weapon]==POW_SMART_MINE)
1404 Players[Player_num].secondary_ammo[Secondary_weapon]-=4;
1406 Players[Player_num].secondary_ammo[Secondary_weapon]--;
1408 if (Players[Player_num].secondary_ammo[Secondary_weapon]==0)
1410 Players[Player_num].secondary_weapon_flags &= (~(1<<Secondary_weapon));
1411 auto_select_weapon (1);
1415 // ---------------------------------------------------------------------------------------
1416 // Do seismic disturbance stuff including the looping sounds with changing volume.
1417 void do_seismic_stuff(void)
1421 stv_save = Seismic_tremor_volume;
1422 Seismic_tremor_magnitude = 0;
1423 Seismic_tremor_volume = 0;
1425 rock_the_mine_frame();
1426 seismic_disturbance_frame();
1428 if (stv_save != 0) {
1429 if (Seismic_tremor_volume == 0) {
1430 digi_stop_looping_sound();
1431 Seismic_sound_playing = 0;
1434 if ((GameTime > Next_seismic_sound_time) && Seismic_tremor_volume) {
1437 volume = Seismic_tremor_volume * 2048;
1440 digi_change_looping_volume(volume);
1441 Next_seismic_sound_time = GameTime + d_rand()/4 + 8192;
1447 int tactile_fire_duration[]={120,80,150,250,150,200,100,180,280,100};
1448 int tactile_fire_repeat[]={260,90,160,160,160,210,110,191,291,111};
1450 void tactile_set_button_jolt ()
1456 static int stickmag=-1;
1459 dur=tactile_fire_duration[Primary_weapon];
1460 rep=tactile_fire_repeat[Primary_weapon];
1466 if (t=FindArg("-stickmag"))
1467 stickmag=atoi (Args[t+1]);
1471 infile=(FILE *)fopen ("stick.val","rt");
1476 fscanf (infile,"%d %d\n",&tactile_fire_duration[i],&tactile_fire_repeat[i]);
1477 mprintf ((0,"scan value[%d]=%d\n",i,tactile_fire_duration[i]));
1482 ButtonReflexJolt (0,stickmag,0,dur,rep);
1488 * reads n weapon_info structs from a CFILE
1490 extern int weapon_info_read_n(weapon_info *wi, int n, CFILE *fp, int file_version)
1494 for (i = 0; i < n; i++) {
1495 wi[i].render_type = cfile_read_byte(fp);
1496 wi[i].persistent = cfile_read_byte(fp);
1497 wi[i].model_num = cfile_read_short(fp);
1498 wi[i].model_num_inner = cfile_read_short(fp);
1500 wi[i].flash_vclip = cfile_read_byte(fp);
1501 wi[i].robot_hit_vclip = cfile_read_byte(fp);
1502 wi[i].flash_sound = cfile_read_short(fp);
1504 wi[i].wall_hit_vclip = cfile_read_byte(fp);
1505 wi[i].fire_count = cfile_read_byte(fp);
1506 wi[i].robot_hit_sound = cfile_read_short(fp);
1508 wi[i].ammo_usage = cfile_read_byte(fp);
1509 wi[i].weapon_vclip = cfile_read_byte(fp);
1510 wi[i].wall_hit_sound = cfile_read_short(fp);
1512 wi[i].destroyable = cfile_read_byte(fp);
1513 wi[i].matter = cfile_read_byte(fp);
1514 wi[i].bounce = cfile_read_byte(fp);
1515 wi[i].homing_flag = cfile_read_byte(fp);
1517 wi[i].speedvar = cfile_read_byte(fp);
1518 wi[i].flags = cfile_read_byte(fp);
1519 wi[i].flash = cfile_read_byte(fp);
1520 wi[i].afterburner_size = cfile_read_byte(fp);
1522 if (file_version >= 3)
1523 wi[i].children = cfile_read_byte(fp);
1525 /* Set the type of children correctly when using old
1526 * datafiles. In earlier descent versions this was simply
1527 * hard-coded in create_smart_children().
1532 wi[i].children = PLAYER_SMART_HOMING_ID;
1535 wi[i].children = SMART_MINE_HOMING_ID;
1537 #if 0 /* not present in shareware */
1538 case ROBOT_SUPERPROX_ID:
1539 wi[i].children = ROBOT_SMART_MINE_HOMING_ID;
1541 case EARTHSHAKER_ID:
1542 wi[i].children = EARTHSHAKER_MEGA_ID;
1546 wi[i].children = -1;
1550 wi[i].energy_usage = cfile_read_fix(fp);
1551 wi[i].fire_wait = cfile_read_fix(fp);
1553 if (file_version >= 3)
1554 wi[i].multi_damage_scale = cfile_read_fix(fp);
1555 else /* FIXME: hack this to set the real values */
1556 wi[i].multi_damage_scale = F1_0;
1558 bitmap_index_read(&wi[i].bitmap, fp);
1560 wi[i].blob_size = cfile_read_fix(fp);
1561 wi[i].flash_size = cfile_read_fix(fp);
1562 wi[i].impact_size = cfile_read_fix(fp);
1563 for (j = 0; j < NDL; j++)
1564 wi[i].strength[j] = cfile_read_fix(fp);
1565 for (j = 0; j < NDL; j++)
1566 wi[i].speed[j] = cfile_read_fix(fp);
1567 wi[i].mass = cfile_read_fix(fp);
1568 wi[i].drag = cfile_read_fix(fp);
1569 wi[i].thrust = cfile_read_fix(fp);
1570 wi[i].po_len_to_width_ratio = cfile_read_fix(fp);
1571 wi[i].light = cfile_read_fix(fp);
1572 wi[i].lifetime = cfile_read_fix(fp);
1573 wi[i].damage_radius = cfile_read_fix(fp);
1574 bitmap_index_read(&wi[i].picture, fp);
1575 if (file_version >= 3)
1576 bitmap_index_read(&wi[i].hires_picture, fp);
1578 wi[i].hires_picture.index = wi[i].picture.index;