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