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