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