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