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