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