]> icculus.org git repositories - taylor/freespace2.git/blob - src/io/keycontrol.cpp
Initial revision
[taylor/freespace2.git] / src / io / keycontrol.cpp
1 /*
2  * $Logfile: /Freespace2/code/Io/KeyControl.cpp $
3  * $Revision$
4  * $Date$
5  * $Author$
6  *
7  * Routines to read and deal with keyboard input.
8  *
9  * $Log$
10  * Revision 1.1  2002/05/03 03:28:09  root
11  * Initial revision
12  *
13  * 
14  * 47    9/09/99 11:40p Dave
15  * Handle an Assert() in beam code. Added supernova sounds. Play the right
16  * 2 end movies properly, based upon what the player did in the mission.
17  * 
18  * 46    9/07/99 11:26p Andsager
19  * Fix "r" targeting key, making evaluate_ship_as_closest_target() and
20  * hud_target_live_turret() consider if turret is targeting player
21  * 
22  * 45    9/03/99 1:31a Dave
23  * CD checking by act. Added support to play 2 cutscenes in a row
24  * seamlessly. Fixed super low level cfile bug related to files in the
25  * root directory of a CD. Added cheat code to set campaign mission # in
26  * main hall.
27  * 
28  * 44    9/01/99 10:09a Dave
29  * Pirate bob.
30  * 
31  * 43    8/27/99 10:36a Dave
32  * Impose a 2% penalty for hitting the shield balance key.
33  * 
34  * 42    8/27/99 9:57a Dave
35  * Enabled standard cheat codes. Allow player to continue in a campaing
36  * after using cheat codes.
37  * 
38  * 41    8/26/99 9:45a Dave
39  * First pass at easter eggs and cheats.
40  * 
41  * 40    8/24/99 1:49a Dave
42  * Fixed client-side afterburner stuttering. Added checkbox for no version
43  * checking on PXO join. Made button info passing more friendly between
44  * client and server.
45  * 
46  * 39    8/22/99 5:53p Dave
47  * Scoring fixes. Added self destruct key. Put callsigns in the logfile
48  * instead of ship designations for multiplayer players.
49  * 
50  * 38    8/19/99 10:59a Dave
51  * Packet loss detection.
52  * 
53  * 37    8/18/99 12:09p Andsager
54  * Add debug if message has no anim for message.  Make messages come from
55  * wing leader.
56  * 
57  * 36    8/05/99 2:05a Dave
58  * Whee.
59  * 
60  * 35    8/01/99 12:39p Dave
61  * Added HUD contrast control key (for nebula).
62  * 
63  * 34    7/31/99 2:30p Dave
64  * Added nifty mission message debug viewing keys.
65  * 
66  * 33    7/21/99 8:10p Dave
67  * First run of supernova effect.
68  * 
69  * 32    7/15/99 4:09p Andsager
70  * Disable cheats for FS2_DEMO
71  * 
72  * 31    7/15/99 9:20a Andsager
73  * FS2_DEMO initial checkin
74  * 
75  * 30    7/07/99 3:32p Dave
76  * Oops. Forgot to remove this.
77  * 
78  * 29    7/02/99 4:31p Dave
79  * Much more sophisticated lightning support.
80  * 
81  * 28    6/10/99 3:43p Dave
82  * Do a better job of syncing text colors to HUD gauges.
83  * 
84  * 27    6/09/99 2:55p Andsager
85  * Allow multiple asteroid subtypes (of large, medium, small) and follow
86  * family.
87  * 
88  * 26    5/24/99 5:45p Dave
89  * Added detail levels to the nebula, with a decent speedup. Split nebula
90  * lightning into its own section.
91  * 
92  * 25    5/08/99 8:25p Dave
93  * Upped object pairs. First run of nebula lightning.
94  * 
95  * 24    5/05/99 9:02p Dave
96  * Fixed D3D aabitmap rendering. Spiffed up nebula effect a bit (added
97  * rotations, tweaked values, made bitmap selection more random). Fixed
98  * D3D beam weapon clipping problem. Added D3d frame dumping.
99  * 
100  * 23    5/03/99 9:07a Dave
101  * Pirate Bob. Changed beam test code a bit.
102  * 
103  * 22    4/21/99 6:15p Dave
104  * Did some serious housecleaning in the beam code. Made it ready to go
105  * for anti-fighter "pulse" weapons. Fixed collision pair creation. Added
106  * a handy macro for recalculating collision pairs for a given object.
107  * 
108  * 21    4/16/99 5:54p Dave
109  * Support for on/off style "stream" weapons. Real early support for
110  * target-painting lasers.
111  * 
112  * 20    3/31/99 8:24p Dave
113  * Beefed up all kinds of stuff, incluging beam weapons, nebula effects
114  * and background nebulae. Added per-ship non-dimming pixel colors.
115  * 
116  * 19    3/29/99 6:17p Dave
117  * More work on demo system. Got just about everything in except for
118  * blowing ships up, secondary weapons and player death/warpout.
119  * 
120  * 18    3/28/99 5:58p Dave
121  * Added early demo code. Make objects move. Nice and framerate
122  * independant, but not much else. Don't use yet unless you're me :)
123  * 
124  * 17    3/09/99 6:24p Dave
125  * More work on object update revamping. Identified several sources of
126  * unnecessary bandwidth.
127  * 
128  * 16    2/21/99 6:01p Dave
129  * Fixed standalone WSS packets. 
130  * 
131  * 15    2/21/99 1:48p Dave
132  * Some code for monitoring datarate for multiplayer in detail.
133  * 
134  * 14    1/21/99 2:06p Dave
135  * Final checkin for multiplayer testing.
136  * 
137  * 13    1/19/99 3:57p Andsager
138  * Round 2 of variables
139  * 
140  * 12    1/12/99 12:53a Dave
141  * More work on beam weapons - made collision detection very efficient -
142  * collide against all object types properly - made 3 movement types
143  * smooth. Put in test code to check for possible non-darkening pixels on
144  * object textures.
145  * 
146  * 11    1/08/99 2:08p Dave
147  * Fixed software rendering for pofview. Super early support for AWACS and
148  * beam weapons.
149  * 
150  * 10    12/06/98 2:36p Dave
151  * Drastically improved nebula fogging.
152  * 
153  * 9     12/04/98 3:37p Andsager
154  * Added comment out asteroid launcher
155  * 
156  * 8     11/19/98 4:19p Dave
157  * Put IPX sockets back in psnet. Consolidated all multiplayer config
158  * files into one.
159  * 
160  * 7     11/05/98 5:55p Dave
161  * Big pass at reducing #includes
162  * 
163  * 6     10/26/98 9:42a Dave
164  * Early flak gun support.
165  * 
166  * 5     10/20/98 1:39p Andsager
167  * Make so sparks follow animated ship submodels.  Modify
168  * ship_weapon_do_hit_stuff() and ship_apply_local_damage() to add
169  * submodel_num.  Add submodel_num to multiplayer hit packet.
170  * 
171  * 4     10/13/98 9:28a Dave
172  * Started neatening up freespace.h. Many variables renamed and
173  * reorganized. Added AlphaColors.[h,cpp]
174  * 
175  * 3     10/09/98 2:57p Dave
176  * Starting splitting up OS stuff.
177  * 
178  * 2     10/07/98 10:53a Dave
179  * Initial checkin.
180  * 
181  * 1     10/07/98 10:49a Dave
182  * 
183  * 387   6/17/98 11:02a Lawrance
184  * show what cheat code is in the comment
185  * 
186  * 386   6/09/98 5:15p Lawrance
187  * French/German localization
188  * 
189  * 385   6/09/98 10:31a Hoffoss
190  * Created index numbers for all xstr() references.  Any new xstr() stuff
191  * added from here on out should be added to the end if the list.  The
192  * current list count can be found in FreeSpace.cpp (search for
193  * XSTR_SIZE).
194  * 
195  * 384   6/01/98 11:43a John
196  * JAS & MK:  Classified all strings for localization.
197  * 
198  * 383   5/24/98 1:46p Mike
199  * Final cheat codes.
200  * 
201  * 382   5/19/98 2:20p Mike
202  * Comment out nprintf().
203  * 
204  * 381   5/19/98 12:19p Mike
205  * Cheat codes!
206  * 
207  * 380   5/19/98 11:11a Lawrance
208  * Make 'G' only target hostiles
209  * 
210  * 379   5/18/98 11:00p Mike
211  * Adding support for cheat system.
212  * 
213  * 378   5/18/98 12:41a Allender
214  * fixed subsystem problems on clients (i.e. not reporting properly on
215  * damage indicator).  Fixed ingame join problem with respawns.  minor
216  * comm menu stuff
217  * 
218  * 377   5/17/98 1:43a Dave
219  * Eradicated chatbox problems. Remove speed match for observers. Put in
220  * help screens for PXO. Fix messaging and end mission privelges. Fixed
221  * team select screen bugs. Misc UI fixes.
222  * 
223  * 376   5/15/98 8:36p Lawrance
224  * Add 'target ship that last sent transmission' target key
225  * 
226  * 375   5/14/98 11:07a Lawrance
227  * Ensure looped sounds get stopped before stopping all channels
228  * 
229  * 374   5/12/98 11:59p Dave
230  * Put in some more functionality for Parallax Online.
231  * 
232  * 373   5/11/98 5:29p Hoffoss
233  * Added mouse button mapped to joystick button support.
234  * 
235  * 372   5/08/98 10:14a Lawrance
236  * Play sound when auto-targeting gets toggled.
237  * 
238  * 371   5/04/98 9:25a Allender
239  * don't allow time compression in multiplayer
240  * 
241  * 370   4/30/98 4:43p Allender
242  * trap player obj when changing dual fire status on ship
243  * 
244  * 369   4/30/98 4:16p Peter
245  * fixes for critical button functions when a player (client) ship is dead
246  * or dying
247  * 
248  * 368   4/27/98 9:03a Dave
249  * Fixed a multiplayer sequencing bug where paused players who were in the
250  * options screen got an Assert when unpausing. Removed an optimiized
251  * build warning in keycontrol. 
252  * 
253  * 367   4/26/98 4:29p Lawrance
254  * Put back time compression keys... somehow they were trashed by a later
255  * checkin.
256  * 
257  * 366   4/25/98 5:36p Mike
258  * Prevent player warpout if engine < 10%.
259  * 
260  * $NoKeywords: $
261  */
262
263 #include "pstypes.h"
264 #include "linklist.h"
265 #include "key.h"
266 #include "joy.h"
267 #include "timer.h"
268 #include "ship.h"
269 #include "player.h"
270 #include "weapon.h"
271 #include "hud.h"
272 #include "contexthelp.h"
273 #include "gamesequence.h"
274 #include "osapi.h"
275 #include "missiongoals.h"
276 #include "hud.h"
277 #include "hudtarget.h"
278 #include "optionsmenu.h"
279 #include "freespace.h"
280 #include "controlsconfig.h"
281 #include "mouse.h"
282 #include "hudets.h"
283 #include "multi.h"
284 #include "multiutil.h"
285 #include "sound.h"
286 #include "gamesnd.h"
287 #include "bmpman.h"
288 #include "rbaudio.h"
289 #include "hudsquadmsg.h"
290 #include "eventmusic.h"
291 #include "animplay.h"
292 #include "freespace.h"
293 #include "cmeasure.h"
294 #include "missionhotkey.h"
295 #include "afterburner.h"
296 #include "missionparse.h"
297 #include "hudescort.h"
298 #include "hudshield.h"
299 #include "multiutil.h"
300 #include "multimsgs.h"
301 #include "keycontrol.h"
302 #include "shiphit.h"
303 #include "shipfx.h"
304 #include "hud.h"
305 #include "hudobserver.h"
306 #include "missionlog.h"
307 #include "hudtargetbox.h"
308 #include "popup.h"
309 #include "objcollide.h"
310 #include "hudconfig.h"
311 #include "missioncampaign.h"
312 #include "rtvoice.h"
313 #include "multi_respawn.h"
314 #include "multi_pmsg.h"
315 #include "crypt.h"
316 #include "ui.h"
317 #include "multi_pause.h"
318 #include "multi_observer.h"
319 #include "multi_endgame.h"
320 #include "beam.h"
321 #include "neblightning.h"
322 #include "supernova.h"
323 #include "missionmessage.h"
324 #include "mainhallmenu.h"
325 #include "aigoals.h"
326
327 // --------------------------------------------------------------
328 // Global to file 
329 // --------------------------------------------------------------
330
331 // --------------------------------------------------------------
332 // Externals
333 // --------------------------------------------------------------
334 typedef struct asteroid_field {
335         vector  min_bound;                                              //      Minimum range of field.
336         vector  max_bound;                                              //      Maximum range of field.
337         vector  vel;                                                            //      Average asteroid moves at this velocity.
338         float           speed;                                                  // Average speed of field
339         int             num_initial_asteroids;          //      Number of asteroids at creation.
340 } asteroid_field;
341
342 #define CHEAT_BUFFER_LEN        20
343 #define CHEATSPOT                               (CHEAT_BUFFER_LEN - 1)
344
345 char CheatBuffer[CHEAT_BUFFER_LEN+1];
346
347 #ifdef FS2_DEMO
348         char *Cheat_code_demo = NOX("33BE^(8]C01(:=BHt");
349 #else
350         char *Cheat_code = NOX("33BE^(8]C01(:=BHt");                                    // www.freespace2.com
351         char *Cheat_code_fish = NOX("bDc9y+$;#AIDRoouM");                       // vasudanswuvfishes
352         char *Cheat_code_headz = NOX("!;:::@>F7L?@@2:@A");                      // humanheadsinside.
353         char *Cheat_code_tooled = NOX("sipp-^rM@L!U^usjX");             // tooledworkedowned
354         char *Cheat_code_pirate = NOX("MAP4YP[4=-2uC(yJ^");             // arrrrwalktheplank    
355         char *Cheat_code_skip = NOX("7!ICkSI\"(8n3JesBP");                      // skipmemymissionyo
356 #endif
357                                                                                   // 666)6=N79+Z45=BE0e
358 int Tool_enabled = 0;
359
360         /*
361 #else 
362         // list of the cheat codes
363         //#ifdef INTERPLAYQA
364         // "DavidPerry" NOX("0!XZQ*K.pu");
365         // NOX("&BvWJe=a?$VP*=@2W,2Y"); // Super-secret 20 character string!
366         //NOX("STs`nHqW\\lv#KD_aCSWN"); //      solveditonceandforall (note double \\ as string contains \.
367         //XSTR:OFF
368         char *Cheat_code_in_game = NOX("///FES)P<A5=7CCB!n10"); //      www.volition-inc.com
369         char *Cheat_code_movies =  NOX("&BvWJe=a?$VP*=@2W,2Y"); // freespacestandsalone
370         char *Cheat_code_pirate = NOX("%,sPzoE>\\+_(Qs#+h-8o");                         // arrwalktheplankmatey
371         //XSTR:ON
372 #endif
373         */
374
375 int All_movies_enabled = 0;
376
377 //int Debug_allowed = 0;
378
379 //#endif
380
381 extern int AI_watch_object;
382 extern int Countermeasures_enabled;
383
384 extern fix Game_time_compression;
385
386 extern float do_subobj_hit_stuff(object *ship_obj, object *other_obj, vector *hitpos, float damage);
387
388 extern void mission_goal_mark_all_true( int type );
389
390 int Normal_key_set[] = {
391         TARGET_NEXT,
392         TARGET_PREV,
393         TARGET_NEXT_CLOSEST_HOSTILE,
394         TARGET_PREV_CLOSEST_HOSTILE,
395         TARGET_NEXT_CLOSEST_FRIENDLY,
396         TARGET_PREV_CLOSEST_FRIENDLY,
397         TARGET_TARGETS_TARGET,
398         TARGET_SHIP_IN_RETICLE,
399         TARGET_LAST_TRANMISSION_SENDER,
400         TARGET_CLOSEST_SHIP_ATTACKING_TARGET,
401         TARGET_CLOSEST_SHIP_ATTACKING_SELF,
402         STOP_TARGETING_SHIP,
403         TOGGLE_AUTO_TARGETING,
404         TARGET_SUBOBJECT_IN_RETICLE,
405         TARGET_PREV_SUBOBJECT,
406         TARGET_NEXT_SUBOBJECT,
407         STOP_TARGETING_SUBSYSTEM,
408
409         TARGET_NEXT_UNINSPECTED_CARGO,
410         TARGET_PREV_UNINSPECTED_CARGO,
411         TARGET_NEWEST_SHIP,
412         TARGET_NEXT_LIVE_TURRET,
413         TARGET_PREV_LIVE_TURRET,
414         TARGET_NEXT_BOMB,
415         TARGET_PREV_BOMB,
416
417         ATTACK_MESSAGE,
418         DISARM_MESSAGE,
419         DISABLE_MESSAGE,
420         ATTACK_SUBSYSTEM_MESSAGE,
421         CAPTURE_MESSAGE,
422         ENGAGE_MESSAGE,
423         FORM_MESSAGE,
424         PROTECT_MESSAGE,
425         COVER_MESSAGE,
426         WARP_MESSAGE,
427         REARM_MESSAGE,
428         IGNORE_MESSAGE,
429         SQUADMSG_MENU,
430
431         VIEW_CHASE,
432         VIEW_OTHER_SHIP,
433
434         SHOW_GOALS,
435         END_MISSION,
436
437         ADD_REMOVE_ESCORT,
438         ESCORT_CLEAR,
439         TARGET_NEXT_ESCORT_SHIP,
440
441         XFER_SHIELD,
442         XFER_LASER,
443         INCREASE_SHIELD,
444         INCREASE_WEAPON,
445         INCREASE_ENGINE,
446         DECREASE_SHIELD,
447         DECREASE_WEAPON,
448         DECREASE_ENGINE,
449         ETS_EQUALIZE,
450         SHIELD_EQUALIZE,
451         SHIELD_XFER_TOP,
452         SHIELD_XFER_BOTTOM,
453         SHIELD_XFER_RIGHT,
454         SHIELD_XFER_LEFT,
455
456         CYCLE_NEXT_PRIMARY,
457         CYCLE_PREV_PRIMARY,
458         CYCLE_SECONDARY,
459         CYCLE_NUM_MISSLES,
460         RADAR_RANGE_CYCLE,
461
462         MATCH_TARGET_SPEED,
463         TOGGLE_AUTO_MATCH_TARGET_SPEED,
464
465         VIEW_EXTERNAL,
466         VIEW_EXTERNAL_TOGGLE_CAMERA_LOCK,
467         LAUNCH_COUNTERMEASURE,
468         ONE_THIRD_THROTTLE,
469         TWO_THIRDS_THROTTLE,
470         PLUS_5_PERCENT_THROTTLE,
471         MINUS_5_PERCENT_THROTTLE,
472         ZERO_THROTTLE,
473         MAX_THROTTLE,
474
475         TARGET_CLOSEST_REPAIR_SHIP,
476
477         MULTI_MESSAGE_ALL,
478         MULTI_MESSAGE_FRIENDLY,
479         MULTI_MESSAGE_HOSTILE,
480         MULTI_MESSAGE_TARGET,
481         MULTI_OBSERVER_ZOOM_TO,
482
483         TIME_SPEED_UP,
484         TIME_SLOW_DOWN,
485
486         TOGGLE_HUD_CONTRAST,
487
488         MULTI_TOGGLE_NETINFO,
489         MULTI_SELF_DESTRUCT
490 };
491
492 int Dead_key_set[] = {
493         TARGET_NEXT,
494         TARGET_PREV,
495         TARGET_NEXT_CLOSEST_HOSTILE,
496         TARGET_PREV_CLOSEST_HOSTILE,
497         TARGET_NEXT_CLOSEST_FRIENDLY,
498         TARGET_PREV_CLOSEST_FRIENDLY,
499         TARGET_TARGETS_TARGET,
500         TARGET_CLOSEST_SHIP_ATTACKING_TARGET,
501         STOP_TARGETING_SHIP,
502         TOGGLE_AUTO_TARGETING,
503         TARGET_SUBOBJECT_IN_RETICLE,
504         TARGET_PREV_SUBOBJECT,
505         TARGET_NEXT_SUBOBJECT,
506         STOP_TARGETING_SUBSYSTEM,
507         TARGET_NEWEST_SHIP,
508         TARGET_NEXT_LIVE_TURRET,
509         TARGET_PREV_LIVE_TURRET,
510         TARGET_NEXT_BOMB,
511         TARGET_PREV_BOMB,
512
513         VIEW_CHASE,
514         VIEW_OTHER_SHIP,
515
516         SHOW_GOALS,
517
518         ADD_REMOVE_ESCORT,
519         ESCORT_CLEAR,
520         TARGET_NEXT_ESCORT_SHIP,
521         TARGET_CLOSEST_REPAIR_SHIP,     
522
523         MULTI_MESSAGE_ALL,
524         MULTI_MESSAGE_FRIENDLY,
525         MULTI_MESSAGE_HOSTILE,
526         MULTI_MESSAGE_TARGET,
527         MULTI_OBSERVER_ZOOM_TO,
528
529         TIME_SPEED_UP,
530         TIME_SLOW_DOWN
531 };
532
533 int Critical_key_set[] = {              
534         CYCLE_SECONDARY,                        
535         CYCLE_NUM_MISSLES,                      
536         INCREASE_WEAPON,                        
537         DECREASE_WEAPON,        
538         INCREASE_SHIELD,                        
539         DECREASE_SHIELD,                        
540         INCREASE_ENGINE,                        
541         DECREASE_ENGINE,                        
542         ETS_EQUALIZE,
543         SHIELD_EQUALIZE,                        
544         SHIELD_XFER_TOP,                        
545         SHIELD_XFER_BOTTOM,                     
546         SHIELD_XFER_LEFT,                       
547         SHIELD_XFER_RIGHT,                      
548         XFER_SHIELD,                    
549         XFER_LASER,                     
550 };
551
552 int Non_critical_key_set[] = {
553         CYCLE_NEXT_PRIMARY,             
554         CYCLE_PREV_PRIMARY,                     
555         MATCH_TARGET_SPEED,                     
556         TOGGLE_AUTO_MATCH_TARGET_SPEED,                 
557         TARGET_NEXT,    
558         TARGET_PREV,                    
559         TARGET_NEXT_CLOSEST_HOSTILE,                    
560         TARGET_PREV_CLOSEST_HOSTILE,                    
561         TOGGLE_AUTO_TARGETING,                  
562         TARGET_NEXT_CLOSEST_FRIENDLY,                   
563         TARGET_PREV_CLOSEST_FRIENDLY,                   
564         TARGET_SHIP_IN_RETICLE,                 
565         TARGET_LAST_TRANMISSION_SENDER,
566         TARGET_CLOSEST_REPAIR_SHIP,                     
567         TARGET_CLOSEST_SHIP_ATTACKING_TARGET,                   
568         STOP_TARGETING_SHIP,                    
569         TARGET_CLOSEST_SHIP_ATTACKING_SELF,                     
570         TARGET_TARGETS_TARGET,                  
571         TARGET_SUBOBJECT_IN_RETICLE,                    
572         TARGET_PREV_SUBOBJECT,                  
573         TARGET_NEXT_SUBOBJECT,                  
574         STOP_TARGETING_SUBSYSTEM,
575         TARGET_NEXT_BOMB,
576         TARGET_PREV_BOMB,
577         TARGET_NEXT_UNINSPECTED_CARGO,
578         TARGET_PREV_UNINSPECTED_CARGO,
579         TARGET_NEWEST_SHIP,
580         TARGET_NEXT_LIVE_TURRET,
581         TARGET_PREV_LIVE_TURRET,
582         ATTACK_MESSAGE,
583         DISARM_MESSAGE,
584         DISABLE_MESSAGE,
585         ATTACK_SUBSYSTEM_MESSAGE,
586         CAPTURE_MESSAGE,
587         ENGAGE_MESSAGE,
588    FORM_MESSAGE,
589         PROTECT_MESSAGE,
590         COVER_MESSAGE,
591         WARP_MESSAGE,
592         IGNORE_MESSAGE,
593         REARM_MESSAGE,
594         VIEW_CHASE,
595         VIEW_EXTERNAL,
596         VIEW_EXTERNAL_TOGGLE_CAMERA_LOCK,
597         VIEW_OTHER_SHIP,
598         RADAR_RANGE_CYCLE,
599         SQUADMSG_MENU,
600         SHOW_GOALS,
601         END_MISSION,
602         ADD_REMOVE_ESCORT,
603         ESCORT_CLEAR,
604         TARGET_NEXT_ESCORT_SHIP,        
605         MULTI_MESSAGE_ALL,
606         MULTI_MESSAGE_FRIENDLY,
607         MULTI_MESSAGE_HOSTILE,
608         MULTI_MESSAGE_TARGET,
609         MULTI_OBSERVER_ZOOM_TO,                 
610         TOGGLE_HUD_CONTRAST,
611
612         MULTI_TOGGLE_NETINFO,
613         MULTI_SELF_DESTRUCT
614 };
615
616
617 // set sizes of the key sets automatically
618 int Normal_key_set_size = sizeof(Normal_key_set) / sizeof(int);
619 int Dead_key_set_size = sizeof(Dead_key_set) / sizeof(int);
620 int Critical_key_set_size = sizeof(Critical_key_set) / sizeof(int);
621 int Non_critical_key_set_size = sizeof(Non_critical_key_set) / sizeof(int);
622
623 // --------------------------------------------------------------
624 // routine to process keys used only for debugging
625 // --------------------------------------------------------------
626 //#ifndef NDEBUG
627
628 void debug_cycle_player_ship(int delta)
629 {
630         if ( Player_obj == NULL )
631                 return;
632
633         int si_index = Ships[Player_obj->instance].ship_info_index;
634         int sanity = 0;
635         ship_info       *sip;
636         while ( TRUE ) {
637                 si_index += delta;
638                 if ( si_index > MAX_SHIP_TYPES ){
639                         si_index = 0;
640                 }
641                 if ( si_index < 0 ){
642                         si_index = MAX_SHIP_TYPES - 1;
643                 }
644                 sip = &Ship_info[si_index];
645                 if ( sip->flags & SIF_PLAYER_SHIP ){
646                         break;
647                 }
648
649                 // just in case
650                 sanity++;
651                 if ( sanity > MAX_SHIP_TYPES ){
652                         break;
653                 }
654         }
655
656         change_ship_type(Player_obj->instance, si_index);
657         HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Player ship changed to %s", 0), Ship_info[si_index].name);                 
658 }
659
660 // cycle targeted ship to next ship in that species
661 void debug_cycle_targeted_ship(int delta)
662 {
663         object          *objp;
664         ship_info       *sip;
665         int                     si_index, species;
666         char                    name[NAME_LENGTH];
667
668         if ( Player_ai->target_objnum == -1 )
669                 return;
670
671         objp = &Objects[Player_ai->target_objnum];
672         if ( objp->type != OBJ_SHIP )
673                 return;
674
675         si_index = Ships[objp->instance].ship_info_index;
676         Assert(si_index != -1 );
677         species = Ship_info[si_index].species;
678
679         int sanity = 0;
680
681         while ( TRUE ) {
682                 si_index += delta;
683                 if ( si_index > MAX_SHIP_TYPES )
684                         si_index = 0;
685                 if ( si_index < 0 )
686                         si_index = MAX_SHIP_TYPES-1;
687
688         
689                 sip = &Ship_info[si_index];
690         
691                 // if it has test in the name, jump over it
692                 strcpy(name, sip->name);
693                 _strlwr(name);
694                 if ( strstr(name,NOX("test")) != NULL )
695                         continue;
696
697                 if ( sip->species == species && (sip->flags & (SIF_FIGHTER | SIF_BOMBER | SIF_TRANSPORT) ) )
698                         break;
699
700                 // just in case
701                 sanity++;
702                 if ( sanity > MAX_SHIP_TYPES )
703                         break;
704         }
705
706         change_ship_type(objp->instance, si_index);
707         HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Changed player target to %s", 1), Ship_info[si_index].name);                       
708 }
709
710 void debug_max_secondary_weapons(object *objp)
711 {
712         int index;
713         ship *shipp = &Ships[objp->instance];
714         ship_info *sip = &Ship_info[shipp->ship_info_index];
715
716         for ( index = 0; index < MAX_SECONDARY_BANKS; index++ ) {
717                 shipp->weapons.secondary_bank_ammo[index] = sip->secondary_bank_ammo_capacity[index];
718         }
719 }
720
721 void debug_change_song(int delta)
722 {
723         char buf[256];
724         if ( event_music_next_soundtrack(delta) != -1 ) {
725                 event_music_get_soundtrack_name(buf);
726                 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Soundtrack changed to: %s", 2), buf);
727
728         } else {
729                 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Event music is not playing", 3));
730         }
731 }
732
733 //extern void set_global_ignore_object(int objnum);
734
735 extern void hud_target_asteroid();
736 extern int Framerate_delay;
737
738 extern void snd_stop_any_sound();
739
740 void process_debug_keys(int k)
741 {
742 #ifdef INTERPLAYQA
743         if ( !Debug_allowed )
744                 return;
745 #endif
746
747         // if ( (k & KEY_DEBUGGED) && (Game_mode & GM_RECORDING_DEMO) )
748                 // return;
749
750         switch (k) {
751                 case KEY_DEBUGGED + KEY_H:
752                         hud_target_toggle_hidden_from_sensors();
753                         break;
754
755                 case KEY_DEBUGGED + KEY_F: 
756                         /*
757                         int i;
758                         for (i=0; i<NUM_HUD_GAUGES; i++) {
759                                 hud_gauge_start_flash(i);
760                         }
761                         */
762                         extern int wacky_scheme;
763                         if(wacky_scheme == 3){
764                                 wacky_scheme = 0;
765                         } else {
766                                 wacky_scheme++;
767                         }
768                         break;
769                 
770                 case KEY_DEBUGGED + KEY_ALTED + KEY_F:
771                         Framerate_delay += 10;
772                         HUD_printf(XSTR( "Framerate delay increased to %i milliseconds per frame.", 4), Framerate_delay);
773                         break;
774
775                 case KEY_DEBUGGED + KEY_ALTED + KEY_SHIFTED + KEY_F:
776                         Framerate_delay -= 10;
777                         if (Framerate_delay < 0)
778                                 Framerate_delay = 0;
779
780                         HUD_printf(XSTR( "Framerate delay decreased to %i milliseconds per frame.", 5), Framerate_delay);
781                         break;
782
783                 case KEY_DEBUGGED + KEY_C:
784                 case KEY_DEBUGGED1 + KEY_C:
785                         // hud_enemymsg_toggle();
786                         if(Player_obj->flags & OF_COLLIDES){
787                                 obj_set_flags(Player_obj, Player_obj->flags & ~(OF_COLLIDES));
788                                 HUD_sourced_printf(HUD_SOURCE_HIDDEN, "Player no longer collides");
789                         } else {
790                                 obj_set_flags(Player_obj, Player_obj->flags | OF_COLLIDES);
791                                 HUD_sourced_printf(HUD_SOURCE_HIDDEN, "Player collides");
792                         }
793                         break;
794
795                 case KEY_DEBUGGED + KEY_SHIFTED + KEY_C:
796                 case KEY_DEBUGGED1 + KEY_SHIFTED + KEY_C:
797                         Countermeasures_enabled = !Countermeasures_enabled;
798                         HUD_printf(XSTR( "Countermeasure firing: %s", 6), Countermeasures_enabled ? XSTR( "ENABLED", 7) : XSTR( "DISABLED", 8));
799                         break;
800
801                 case KEY_DEBUGGED + KEY_E:
802                         gameseq_post_event(GS_EVENT_EVENT_DEBUG);
803                         break;
804
805                 case KEY_DEBUGGED + KEY_COMMA:
806                         if ( Game_time_compression > (F1_0/4) ){                // can't compress below 0.25
807                                 Game_time_compression /= 2;
808                         }
809                         break;
810                 case KEY_DEBUGGED + KEY_PERIOD:
811                         if ( Game_time_compression < (F1_0*8) ){
812                                 Game_time_compression *= 2;
813                         }
814                         break;
815
816                 //      Kill! the currently targeted ship.
817                 case KEY_DEBUGGED + KEY_K:
818                 case KEY_DEBUGGED1 + KEY_K:
819                         if (Player_ai->target_objnum != -1) {
820                                 object  *objp = &Objects[Player_ai->target_objnum];
821
822                                 switch (objp->type) {
823                                 case OBJ_SHIP:
824                                         ship_apply_local_damage( objp, Player_obj, &objp->pos, 100000.0f, MISS_SHIELDS, CREATE_SPARKS);
825                                         ship_apply_local_damage( objp, Player_obj, &objp->pos, 1.0f, MISS_SHIELDS, CREATE_SPARKS);
826                                         break;
827                                 case OBJ_WEAPON:
828                                         Weapons[objp->instance].lifeleft = 0.01f;
829                                         break;
830                                 }
831                         }
832
833                         break;
834                 
835                 // play the next mission message
836                 case KEY_DEBUGGED + KEY_V:              
837                         extern int Message_debug_index;
838                         extern int Num_messages_playing;
839                         // stop any other messages
840                         if(Num_messages_playing){
841                                 message_kill_all(1);
842                         }
843
844                         // next message
845                         if(Message_debug_index >= Num_messages - 1){
846                                 Message_debug_index = Num_builtin_messages;
847                         } else {
848                                 Message_debug_index++;
849                         }
850                         
851                         // play the message
852                         message_send_unique_to_player( Messages[Message_debug_index].name, Message_waves[Messages[Message_debug_index].wave_info.index].name, MESSAGE_SOURCE_SPECIAL, MESSAGE_PRIORITY_HIGH, 0, 0 );                    
853                         if (Messages[Message_debug_index].avi_info.index == -1) {
854                                 HUD_printf("No anim set for message \"%s\"; None will play!", Messages[Message_debug_index].name);
855                         }
856                         break;
857
858                 // play the previous mission message
859                 case KEY_DEBUGGED + KEY_SHIFTED + KEY_V:
860                         extern int Message_debug_index;
861                         extern int Num_messages_playing;
862                         // stop any other messages
863                         if(Num_messages_playing){
864                                 message_kill_all(1);
865                         }
866
867                         // go maybe go down one
868                         if(Message_debug_index == Num_builtin_messages - 1){
869                                 Message_debug_index = Num_builtin_messages;
870                         } else if(Message_debug_index > Num_builtin_messages){
871                                 Message_debug_index--;
872                         }
873                         
874                         // play the message
875                         message_send_unique_to_player( Messages[Message_debug_index].name, Message_waves[Messages[Message_debug_index].wave_info.index].name, MESSAGE_SOURCE_SPECIAL, MESSAGE_PRIORITY_HIGH, 0, 0 );
876                         if (Messages[Message_debug_index].avi_info.index == -1) {
877                                 HUD_printf("No avi associated with this message; None will play!");
878                         }
879                         break;
880
881                 // reset to the beginning of mission messages
882                 case KEY_DEBUGGED + KEY_ALTED + KEY_V:
883                         extern int Message_debug_index;
884                         Message_debug_index = Num_builtin_messages - 1;
885                         HUD_printf("Resetting to first mission message");
886                         break;
887
888                 //      Kill! the currently targeted ship.
889                 case KEY_DEBUGGED + KEY_ALTED + KEY_SHIFTED + KEY_K:
890                 case KEY_DEBUGGED1 + KEY_ALTED + KEY_SHIFTED + KEY_K:
891                         if (Player_ai->target_objnum != -1) {
892                                 object  *objp = &Objects[Player_ai->target_objnum];
893
894                                 if (objp->type == OBJ_SHIP) {
895                                         ship_apply_local_damage( objp, Player_obj, &objp->pos, Ship_info[Ships[objp->instance].ship_info_index].initial_hull_strength * 0.1f + 10.0f, MISS_SHIELDS, CREATE_SPARKS);
896                                 }
897                         }
898                         break;
899
900                         //      Kill the currently targeted subsystem.
901                 case KEY_DEBUGGED + KEY_SHIFTED + KEY_K:
902                 case KEY_DEBUGGED1 + KEY_SHIFTED + KEY_K:
903                         if ((Player_ai->target_objnum != -1) && (Player_ai->targeted_subsys != NULL)) {
904                                 object  *objp = &Objects[Player_ai->target_objnum];
905                                 if ( objp->type == OBJ_SHIP ) {
906                                         ship            *sp = &Ships[objp->instance];
907                                         vector  g_subobj_pos;
908
909                                         get_subsystem_world_pos(objp, Player_ai->targeted_subsys, &g_subobj_pos);
910
911                                         do_subobj_hit_stuff(objp, Player_obj, &g_subobj_pos, (float) -Player_ai->targeted_subsys->system_info->type); //100.0f);
912
913                                         if ( sp->subsys_info[SUBSYSTEM_ENGINE].current_hits <= 0.0f ) {
914                                                 mission_log_add_entry(LOG_SHIP_DISABLED, sp->ship_name, NULL );
915                                                 sp->flags |= SF_DISABLED;                               // add the disabled flag
916                                         }
917
918                                         if ( sp->subsys_info[SUBSYSTEM_TURRET].current_hits <= 0.0f ) {
919                                                 mission_log_add_entry(LOG_SHIP_DISARMED, sp->ship_name, NULL );
920                                                 // sp->flags |= SF_DISARMED;                            // add the disarmed flag
921                                         }
922                                 }
923                         }
924                         break;
925
926                 case KEY_DEBUGGED + KEY_ALTED + KEY_K:
927                 case KEY_DEBUGGED1 + KEY_ALTED + KEY_K:
928                         {
929                                 float   shield, integrity;
930                                 vector  pos, randvec;
931
932                                 vm_vec_rand_vec_quick(&randvec);
933                                 vm_vec_scale_add(&pos, &Player_obj->pos, &randvec, Player_obj->radius);
934                         ship_apply_local_damage(Player_obj, Player_obj, &pos, 25.0f, MISS_SHIELDS, CREATE_SPARKS);
935                         hud_get_target_strength(Player_obj, &shield, &integrity);
936                         HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "You knocked yourself down to %7.3f percent hull.\n", 9), 100.0f * integrity);
937                         break;
938                         }
939                         
940                 //      Whack down the player's shield and hull by a little more than 50%
941                 //      Select next object to be viewed by AI.
942                 case KEY_DEBUGGED + KEY_I:
943                 case KEY_DEBUGGED1 + KEY_I:
944                         Player_obj->flags ^= OF_INVULNERABLE;
945                         HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "You are %s", 10), Player_obj->flags & OF_INVULNERABLE ? XSTR( "now INVULNERABLE!", 11) : XSTR( "no longer invulnerable...", 12));
946                         break;
947
948                 case KEY_DEBUGGED + KEY_SHIFTED + KEY_I:
949                 case KEY_DEBUGGED1 + KEY_SHIFTED + KEY_I:
950                         if (Player_ai->target_objnum != -1) {
951                                 object  *objp = &Objects[Player_ai->target_objnum];
952
953                                 objp->flags ^= OF_INVULNERABLE;
954                                 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Player's target [%s] is %s", 13), Ships[objp->instance].ship_name, objp->flags & OF_INVULNERABLE ? XSTR( "now INVULNERABLE!", 11) : XSTR( "no longer invulnerable...", 12));
955                         }
956                         break;
957 /*
958                 case KEY_DEBUGGED + KEY_ALTED + KEY_I:
959                         if (Player_ai->target_objnum != -1)
960                                 set_global_ignore_object(Player_ai->target_objnum);
961                         break;
962 */
963
964                 case KEY_DEBUGGED + KEY_N:
965                         AI_watch_object++;
966                         HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Spewing debug info about object #%d", 14), AI_watch_object);
967                         break;
968
969                 case KEY_DEBUGGED + KEY_O:
970                 // case KEY_DEBUGGED1 + KEY_O:
971                         toggle_player_object();
972                         break;                          
973
974                 case KEY_DEBUGGED + KEY_SHIFTED + KEY_O:
975                         extern int Debug_octant;
976                         if(Debug_octant == 7){
977                                 Debug_octant = -1;
978                         } else {
979                                 Debug_octant++;
980                         }
981                         nprintf(("General", "Debug_octant == %d\n", Debug_octant));
982                         break;
983
984                 case KEY_DEBUGGED + KEY_P:
985                         supernova_start(20);
986                         break;
987
988                 case KEY_DEBUGGED + KEY_W:
989                 case KEY_DEBUGGED1 + KEY_W:
990                 case KEY_DEBUGGED + KEY_SHIFTED + KEY_W:
991                 case KEY_DEBUGGED1 + KEY_SHIFTED + KEY_W:
992                         // temp code for testing purposes, toggles weapon energy cheat
993                         Weapon_energy_cheat = !Weapon_energy_cheat;
994                         if (Weapon_energy_cheat) {
995                                 if (k & KEY_SHIFTED)
996                                         HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Weapon energy and missile count will always be at full ALL SHIPS!", 15));
997                                 else
998                                         HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Weapon energy and missile count will always be at full for player", 16));
999
1000                                 debug_max_secondary_weapons(Player_obj);
1001                                 if (k & KEY_SHIFTED) {
1002                                         object  *objp;
1003
1004                                         for ( objp = GET_FIRST(&obj_used_list); objp !=END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp) )
1005                                                 if (objp->type == OBJ_SHIP)
1006                                                         debug_max_secondary_weapons(objp);
1007                                 }
1008
1009                         } else
1010                                 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Normal weapon energy system / missile count restored", 17));
1011
1012                         break;
1013
1014                 case KEY_DEBUGGED + KEY_G:
1015                 // case KEY_DEBUGGED1 + KEY_G:
1016                         mission_goal_mark_all_true( PRIMARY_GOAL );
1017                         break;
1018
1019                 case KEY_DEBUGGED + KEY_G + KEY_SHIFTED:
1020                 // case KEY_DEBUGGED1 + KEY_G + KEY_SHIFTED:
1021                         mission_goal_mark_all_true( SECONDARY_GOAL );
1022                         break;
1023
1024                 case KEY_DEBUGGED + KEY_G + KEY_ALTED:
1025                 // case KEY_DEBUGGED1 + KEY_G + KEY_ALTED:
1026                         mission_goal_mark_all_true( BONUS_GOAL );
1027                         break;
1028
1029                 case KEY_DEBUGGED + KEY_9: {
1030                 case KEY_DEBUGGED1 + KEY_9:
1031                         ship* shipp;
1032
1033                         shipp = &Ships[Player_obj->instance];
1034                         shipp->weapons.secondary_bank_weapons[shipp->weapons.current_secondary_bank]++;
1035                         if ( shipp->weapons.secondary_bank_weapons[shipp->weapons.current_secondary_bank] >= Num_weapon_types )
1036                                 shipp->weapons.secondary_bank_weapons[shipp->weapons.current_secondary_bank] = First_secondary_index;
1037
1038                         HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Secondary Weapon forced to %s", 18), Weapon_info[shipp->weapons.secondary_bank_weapons[shipp->weapons.current_secondary_bank]].name);
1039                         break;
1040                 }
1041
1042                         /*
1043                 case KEY_DEBUGGED + KEY_SHIFTED + KEY_9: {
1044                 case KEY_DEBUGGED1 + KEY_SHIFTED + KEY_9:
1045                         ship* shipp;
1046
1047                         shipp = &Ships[Player_obj->instance];
1048                         shipp->weapons.secondary_bank_weapons[shipp->weapons.current_secondary_bank]--;
1049                         if ( shipp->weapons.secondary_bank_weapons[shipp->weapons.current_secondary_bank] < 0)
1050                                 shipp->weapons.secondary_bank_weapons[shipp->weapons.current_secondary_bank] = Num_weapon_types - 1;
1051
1052                         HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Secondary Weapon forced to %s", 18), Weapon_info[shipp->weapons.secondary_bank_weapons[shipp->weapons.current_secondary_bank]].name);
1053                         break;
1054                 }
1055                 */
1056
1057 #ifndef FS2_DEMO
1058                 case KEY_DEBUGGED + KEY_U: {
1059                 case KEY_DEBUGGED1 + KEY_U:
1060                         // launch asteroid
1061                         extern asteroid_field Asteroid_field;
1062                         object *asteroid_create(asteroid_field *asfieldp, int asteroid_type, int subtype);
1063                         object *objp = asteroid_create(&Asteroid_field, 0, 0);
1064                         vector vel;
1065                         vm_vec_copy_scale(&vel, &Player_obj->orient.fvec, 50.0f);
1066                         objp->phys_info.vel = vel;
1067                         objp->phys_info.desired_vel = vel;
1068                         objp->pos = Player_obj->pos;
1069                         //mission_goal_mark_all_true( PRIMARY_GOAL );
1070                         break;
1071                 }
1072 #endif
1073
1074                 case KEY_DEBUGGED + KEY_0: {
1075                 case KEY_DEBUGGED1 + KEY_0:
1076                         ship* shipp;
1077
1078                         shipp = &Ships[Player_obj->instance];
1079                         shipp->weapons.primary_bank_weapons[shipp->weapons.current_primary_bank]++;
1080                         if ( shipp->weapons.primary_bank_weapons[shipp->weapons.current_primary_bank] >= First_secondary_index )
1081                                 shipp->weapons.primary_bank_weapons[shipp->weapons.current_primary_bank] = 0;
1082
1083                         HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Primary Weapon forced to %s", 19), Weapon_info[shipp->weapons.primary_bank_weapons[shipp->weapons.current_primary_bank]].name);
1084                         break;
1085                 }
1086
1087                 case KEY_DEBUGGED + KEY_SHIFTED + KEY_0: {
1088                 case KEY_DEBUGGED1 + KEY_SHIFTED + KEY_0:
1089                         ship* shipp;
1090
1091                         shipp = &Ships[Player_obj->instance];
1092                         shipp->weapons.primary_bank_weapons[shipp->weapons.current_primary_bank]--;
1093                         if ( shipp->weapons.primary_bank_weapons[shipp->weapons.current_primary_bank] < 0)
1094                                 shipp->weapons.primary_bank_weapons[shipp->weapons.current_primary_bank] = First_secondary_index-1 ;
1095
1096                         HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Primary Weapon forced to %s", 19), Weapon_info[shipp->weapons.primary_bank_weapons[shipp->weapons.current_primary_bank]].name);
1097                         break;
1098                 }
1099
1100                 case KEY_DEBUGGED + KEY_J: {
1101                         int new_pattern = event_music_return_current_pattern();
1102
1103                         new_pattern++;
1104                         if ( new_pattern >= MAX_PATTERNS )
1105                                 new_pattern = 0;
1106
1107                         event_music_change_pattern(new_pattern);
1108                         break;
1109                 }
1110
1111                 case KEY_DEBUGGED + KEY_M: {
1112                         if ( Event_music_enabled ) {
1113                                 event_music_disable();
1114                                 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Event music disabled", 20));
1115
1116                         } else {
1117                                 event_music_enable();
1118                                 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Event music enabled", 21));
1119                         }
1120
1121                         break;
1122                 }
1123
1124                 case KEY_DEBUGGED + KEY_R: {
1125                 // case KEY_DEBUGGED1 + KEY_R:
1126                         if (Player_ai->target_objnum != -1)
1127                                 ai_issue_rearm_request(&Objects[Player_ai->target_objnum]);
1128                         else
1129                                 ai_issue_rearm_request(Player_obj);
1130
1131                         break;
1132                 }
1133
1134                 case KEY_DEBUGGED + KEY_SHIFTED + KEY_UP:
1135                         Game_detail_level++;
1136                         HUD_printf( XSTR( "Detail level set to %+d\n", 22), Game_detail_level );
1137                         break;
1138
1139                 case KEY_DEBUGGED + KEY_SHIFTED + KEY_DOWN:
1140                         Game_detail_level--;
1141                         HUD_printf( XSTR( "Detail level set to %+d\n", 22), Game_detail_level );
1142                         break;
1143
1144 #ifndef NDEBUG
1145                 case KEY_DEBUGGED + KEY_SHIFTED + KEY_T:        {
1146                         extern int Test_begin;
1147
1148                         if ( Test_begin == 1 )
1149                                 break;
1150
1151                         Test_begin = 1;
1152                         HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Frame Rate test started", 23));
1153
1154                         break;
1155                 }
1156 #endif
1157                 case KEY_DEBUGGED + KEY_D:
1158                         extern int OO_update_index;                     
1159
1160                         if(MULTIPLAYER_MASTER){
1161                                 do {
1162                                         OO_update_index++;
1163                                 } while((OO_update_index < (MAX_PLAYERS-1)) && !MULTI_CONNECTED(Net_players[OO_update_index]));
1164                                 if(OO_update_index >= MAX_PLAYERS-1){
1165                                         OO_update_index = -1;
1166                                 }                       
1167                         } else {
1168                                 if(OO_update_index < 0){
1169                                         OO_update_index = MY_NET_PLAYER_NUM;
1170                                 } else {
1171                                         OO_update_index = -1;
1172                                 }
1173                         }
1174                         break;
1175
1176                 // change player ship to next flyable type
1177                 case KEY_DEBUGGED + KEY_RIGHT:
1178                         debug_cycle_player_ship(1);
1179                         break;
1180
1181                 // change player ship to previous flyable ship
1182                 case KEY_DEBUGGED + KEY_LEFT:
1183                         debug_cycle_player_ship(-1);
1184                         break;
1185                 
1186                 // cycle target to ship
1187                 case KEY_DEBUGGED + KEY_SHIFTED + KEY_RIGHT:
1188                         debug_cycle_targeted_ship(1);
1189                         break;
1190
1191                 // cycle target to previous ship
1192                 case KEY_DEBUGGED + KEY_SHIFTED + KEY_LEFT:
1193                         debug_cycle_targeted_ship(-1);
1194                         break;
1195
1196                 // change species of the targeted ship
1197                 case KEY_DEBUGGED + KEY_S: {
1198                         if ( Player_ai->target_objnum < 0 )
1199                                 break;
1200
1201                         object          *objp;
1202                         ship_info       *sip;
1203
1204                         objp = &Objects[Player_ai->target_objnum];
1205                         if ( objp->type != OBJ_SHIP )
1206                                 return;
1207
1208                         sip = &Ship_info[Ships[objp->instance].ship_info_index];
1209                         sip->species++;
1210                         if ( sip->species > SPECIES_SHIVAN )
1211                                 sip->species = 0;
1212
1213                         HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Species of target changed to: %s", 24), Species_names[sip->species]);
1214                         break;
1215                 }
1216                         
1217                 case KEY_DEBUGGED + KEY_SHIFTED + KEY_S:
1218                         game_increase_skill_level();
1219                         HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Skill level set to %s.", 25), Skill_level_names(Game_skill_level));
1220                         break;
1221
1222                 // kill all missiles
1223                 case KEY_DEBUGGED + KEY_SHIFTED + KEY_1:
1224                         beam_test(1);
1225                         break;                          
1226                 case KEY_DEBUGGED + KEY_SHIFTED + KEY_2:
1227                         beam_test(2);
1228                         break;          
1229                 case KEY_DEBUGGED + KEY_SHIFTED + KEY_3:
1230                         beam_test(3);
1231                         break;                          
1232                 case KEY_DEBUGGED + KEY_SHIFTED + KEY_4:
1233                         beam_test(4);
1234                         break;          
1235                 case KEY_DEBUGGED + KEY_SHIFTED + KEY_5:
1236                         beam_test(5);
1237                         break;                          
1238                 case KEY_DEBUGGED + KEY_SHIFTED + KEY_6:
1239                         beam_test(6);
1240                         break;          
1241                 case KEY_DEBUGGED + KEY_SHIFTED + KEY_7:
1242                         beam_test(7);
1243                         break;                          
1244                 case KEY_DEBUGGED + KEY_SHIFTED + KEY_8:
1245                         beam_test(8);
1246                         break;          
1247                 case KEY_DEBUGGED + KEY_SHIFTED + KEY_9:
1248                         beam_test(9);
1249                         break;                          
1250
1251                 case KEY_DEBUGGED + KEY_CTRLED + KEY_1:
1252                         beam_test_new(1);
1253                         break;                          
1254                 case KEY_DEBUGGED + KEY_CTRLED + KEY_2:
1255                         beam_test_new(2);
1256                         break;          
1257                 case KEY_DEBUGGED + KEY_CTRLED + KEY_3:
1258                         beam_test_new(3);
1259                         break;
1260                                         
1261                 case KEY_DEBUGGED + KEY_T: {
1262                         char buf[256];
1263                         event_music_get_info(buf);
1264                         HUD_sourced_printf(HUD_SOURCE_HIDDEN, buf);
1265                         break;
1266                 }
1267
1268                 case KEY_DEBUGGED + KEY_UP:
1269                         debug_change_song(1);
1270                         break;
1271
1272                 case KEY_DEBUGGED + KEY_DOWN:
1273                         debug_change_song(-1);
1274                         break;
1275
1276                 case KEY_PADMINUS: {
1277                         int init_flag = 0;
1278
1279                         if ( keyd_pressed[KEY_1] )      {
1280                                 init_flag = 1;
1281                                 HUD_color_red -= 4;
1282                         } 
1283
1284                         if ( keyd_pressed[KEY_2] )      {
1285                                 init_flag = 1;
1286                                 HUD_color_green -= 4;
1287                         } 
1288
1289                         if ( keyd_pressed[KEY_3] )      {
1290                                 init_flag = 1;
1291                                 HUD_color_blue -= 4;
1292                         } 
1293
1294                         if (init_flag)
1295                                 HUD_init_colors();
1296
1297                         break;
1298                 }
1299                 
1300                 case KEY_DEBUGGED + KEY_Y:
1301                         /*
1302                         // blast a debug lightning bolt in front of the player
1303                         vector start, strike;
1304                         
1305                         vm_vec_scale_add(&start, &Player_obj->pos, &Player_obj->orient.fvec, 300.0f);
1306                         vm_vec_scale_add2(&start, &Player_obj->orient.rvec, -300.0f);
1307                         vm_vec_scale_add(&strike, &start, &Player_obj->orient.rvec, 600.0f);
1308                         nebl_bolt(DEBUG_BOLT, &start, &strike);
1309                         */
1310                         extern int tst;
1311                         tst = 2;
1312                         break;
1313
1314                 case KEY_PADPLUS: {
1315                         int init_flag = 0;
1316
1317                         if ( keyd_pressed[KEY_1] )      {
1318                                 init_flag = 1;
1319                                 HUD_color_red += 4;
1320                         } 
1321
1322                         if ( keyd_pressed[KEY_2] )      {
1323                                 init_flag = 1;
1324                                 HUD_color_green += 4;
1325                         } 
1326
1327                         if ( keyd_pressed[KEY_3] )      {
1328                                 init_flag = 1;
1329                                 HUD_color_blue += 4;
1330                         } 
1331
1332                         if (init_flag)
1333                                 HUD_init_colors();
1334
1335                         break;
1336                 }
1337         }       // end switch
1338
1339 }
1340 //#endif
1341
1342 void ppsk_hotkeys(int k)
1343 {
1344
1345 #ifndef FS2_DEMO
1346
1347         // use k to check for keys that can have Shift,Ctrl,Alt,Del status
1348         int hotkey_set;
1349
1350 #ifndef NDEBUG
1351         k &= ~KEY_DEBUGGED;                     // since hitting F11 will set this bit
1352 #endif
1353
1354         switch (k) {
1355                 case KEY_F5:
1356                 case KEY_F6:
1357                 case KEY_F7:
1358                 case KEY_F8:
1359                 case KEY_F9:
1360                 case KEY_F10:
1361                 case KEY_F11:
1362                 case KEY_F12:
1363                         hotkey_set = mission_hotkey_get_set_num(k);
1364                         if ( !(Players[Player_num].flags & PLAYER_FLAGS_MSG_MODE) )
1365                                 hud_target_hotkey_select( hotkey_set );
1366                         else
1367                                 hud_squadmsg_hotkey_select( hotkey_set );
1368
1369                         break;
1370
1371                 case KEY_F5 + KEY_SHIFTED:
1372                 case KEY_F6 + KEY_SHIFTED:
1373                 case KEY_F7 + KEY_SHIFTED:
1374                 case KEY_F8 + KEY_SHIFTED:
1375                 case KEY_F9 + KEY_SHIFTED:
1376                 case KEY_F10 + KEY_SHIFTED:
1377                 case KEY_F11 + KEY_SHIFTED:
1378                 case KEY_F12 + KEY_SHIFTED:
1379                         hotkey_set = mission_hotkey_get_set_num(k&(~KEY_SHIFTED));
1380                         mprintf(("Adding to set %d\n", hotkey_set+1));
1381                         if ( Player_ai->target_objnum == -1)
1382                                 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "No target to add/remove from set %d.", 26), hotkey_set+1);
1383                         else  {
1384                                 hud_target_hotkey_add_remove( hotkey_set, &Objects[Player_ai->target_objnum], HOTKEY_USER_ADDED);
1385                                 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "%s added to set %d. (F%d)", 27), Ships[Objects[Player_ai->target_objnum].instance].ship_name, hotkey_set, 4+hotkey_set+1);
1386                         }
1387
1388                         break;
1389
1390                 case KEY_F5 + KEY_SHIFTED + KEY_ALTED:
1391                 case KEY_F6 + KEY_SHIFTED + KEY_ALTED:
1392                 case KEY_F7 + KEY_SHIFTED + KEY_ALTED:
1393                 case KEY_F8 + KEY_SHIFTED + KEY_ALTED:
1394                 case KEY_F9 + KEY_SHIFTED + KEY_ALTED:
1395                 case KEY_F10 + KEY_SHIFTED + KEY_ALTED:
1396                 case KEY_F11 + KEY_SHIFTED + KEY_ALTED:
1397                 case KEY_F12 + KEY_SHIFTED + KEY_ALTED:
1398                         hotkey_set = mission_hotkey_get_set_num(k & ~KEY_SHIFTED+KEY_ALTED);
1399                         hud_target_hotkey_clear( hotkey_set );
1400                         break;
1401
1402                 case KEY_SHIFTED + KEY_MINUS:
1403                         if ( HUD_color_alpha > HUD_COLOR_ALPHA_USER_MIN )       {
1404                                 HUD_color_alpha--;
1405                                 HUD_init_colors();
1406                         }
1407                         break;
1408 /*              case KEY_SHIFTED + KEY_U:
1409                         {
1410                         object *debris_create(object *source_obj, int model_num, int submodel_num, vector *pos, vector *exp_center, int hull_flag, float exp_force);
1411
1412                         object *temp = debris_create(Player_obj, Ships[0].modelnum, model_get(Ships[0].modelnum)->debris_objects[0], &Player_obj->pos, &Player_obj->pos, 1, 1.0f);
1413                         if (temp) {
1414                                 temp->hull_strength = 5000.0f;
1415                                 int objnum = temp - Objects;
1416                                 vm_vec_copy_scale(&Objects[objnum].phys_info.vel, &Player_obj->orient.fvec, 30.0f);
1417                         }
1418                         }
1419                         break;
1420 */
1421
1422                 case KEY_SHIFTED + KEY_EQUAL:
1423                         if ( HUD_color_alpha < HUD_COLOR_ALPHA_USER_MAX ) {
1424                                 HUD_color_alpha++;
1425                                 HUD_init_colors();
1426                         }
1427                         break;
1428         }       // end switch
1429
1430 #endif
1431
1432 }
1433
1434 // check keypress 'key' against a set of valid controls and mark the match in the
1435 // player's button info bitfield.  Also checks joystick controls in the set.
1436 //
1437 // key = scancode (plus modifiers).
1438 // count = total size of the list
1439 // list = list of Control_config struct action indices to check for
1440 void process_set_of_keys(int key, int count, int *list)
1441 {
1442         int i;
1443
1444         for (i=0; i<count; i++)
1445                 if (check_control(list[i], key))
1446                         button_info_set(&Player->bi, list[i]);
1447 }
1448
1449 // routine to process keys used for player ship stuff (*not* ship movement).
1450 void process_player_ship_keys(int k)
1451 {
1452         int masked_k;
1453
1454         masked_k = k & ~KEY_CTRLED;     // take out CTRL modifier only  
1455
1456         // moved this line to beginning of function since hotkeys now encompass
1457         // F5 - F12.  We can return after using F11 as a hotkey.
1458         ppsk_hotkeys(masked_k);
1459         if (keyd_pressed[KEY_DEBUG_KEY]){
1460                 return;
1461         }
1462
1463         // if we're in supernova mode. do nothing
1464         if(Player->control_mode == PCM_SUPERNOVA){
1465                 return;
1466         }
1467
1468         // pass the key to the squadmate messaging code.  If the messaging code took the key, then return
1469         // from here immediately since we don't want to do further key processing.
1470         if ( hud_squadmsg_read_key(k) )
1471                 return;
1472
1473         if ( Player->control_mode == PCM_NORMAL )       {
1474                 //      The following things are not legal to do while dead.
1475                 if ( !(Game_mode & GM_DEAD) ) {
1476                         process_set_of_keys(masked_k, Normal_key_set_size, Normal_key_set);
1477                 } else  {
1478                         process_set_of_keys(masked_k, Dead_key_set_size, Dead_key_set);
1479                 }
1480         } else {
1481
1482         }
1483 }
1484
1485 // Handler for when player hits 'ESC' during the game
1486 void game_do_end_mission_popup()
1487 {
1488         int     pf_flags, choice;
1489 //      char    savegame_filename[_MAX_FNAME];
1490
1491         // do the multiplayer version of this
1492         if(Game_mode & GM_MULTIPLAYER){
1493                 multi_quit_game(PROMPT_ALL);
1494         } else {
1495
1496                 // single player version....
1497                 // do housekeeping things.
1498                 game_stop_time();
1499                 game_stop_looped_sounds();
1500                 snd_stop_all();
1501
1502                 pf_flags = PF_BODY_BIG | PF_USE_AFFIRMATIVE_ICON | PF_USE_NEGATIVE_ICON;
1503                 choice = popup(pf_flags, 3, POPUP_NO, XSTR( "&Yes, Quit", 28), XSTR( "Yes, &Restart", 29), XSTR( "Do you really want to end the mission?", 30));
1504
1505                 switch (choice) {
1506                 case 1:
1507                         // save the game before quitting if in campaign mode
1508                         // MWA -- 3/26/98 -- no more save/restore!!!!
1509 /*
1510                         if ( Game_mode & GM_CAMPAIGN_MODE ) {
1511                                 memset(savegame_filename, 0, _MAX_FNAME);
1512                                 mission_campaign_savefile_generate_root(savegame_filename);
1513                                 strcat(savegame_filename, NOX("svg"));
1514                                 if ( state_save_all(savegame_filename) ) {
1515                                         Int3(); // could not save this game
1516                                 }
1517                         }
1518 */
1519                         gameseq_post_event(GS_EVENT_END_GAME);
1520                         break;
1521
1522                 case 2:
1523                         gameseq_post_event(GS_EVENT_ENTER_GAME);
1524                         break;
1525
1526                 default:
1527                         break;  // do nothing
1528                 }
1529
1530                 game_start_time();
1531                 game_flush();
1532         }
1533 }
1534
1535 // handle pause keypress
1536 void game_process_pause_key()
1537 {
1538         // special processing for multiplayer
1539         if (Game_mode & GM_MULTIPLAYER) {                                                       
1540                 if(Multi_pause_status){
1541                         multi_pause_request(0);
1542                 } else {
1543                         multi_pause_request(1);
1544                 }               
1545         } else {
1546                 gameseq_post_event( GS_EVENT_PAUSE_GAME );
1547         }
1548 }
1549
1550 #define WITHIN_BBOX()   do { \
1551         float scale = 2.0f; \
1552         polymodel *pm = model_get(s_check->modelnum); \
1553         collided = 0; \
1554         if(pm != NULL){ \
1555                 vector temp = new_obj->pos; \
1556                 vector gpos; \
1557                 vm_vec_sub2(&temp, &hit_check->pos); \
1558                 vm_vec_rotate(&gpos, &temp, &hit_check->orient); \
1559                 if((gpos.x >= pm->mins.x * scale) && (gpos.y >= pm->mins.y * scale) && (gpos.z >= pm->mins.z * scale) && (gpos.x <= pm->maxs.x * scale) && (gpos.y <= pm->maxs.y * scale) && (gpos.z <= pm->maxs.z * scale)) { \
1560                         collided = 1; \
1561                 } \
1562         } \
1563 } while(0)
1564
1565 #define MOVE_AWAY_BBOX() do { \
1566         polymodel *pm = model_get(s_check->modelnum); \
1567         if(pm != NULL){ \
1568                 switch((int)frand_range(0.0f, 3.9f)){ \
1569                 case 0: \
1570                         new_obj->pos.x += 200.0f; \
1571                         break; \
1572                 case 1: \
1573                         new_obj->pos.x -= 200.0f; \
1574                         break; \
1575                 case 2: \
1576                         new_obj->pos.y += 200.0f; \
1577                         break; \
1578                 case 3: \
1579                         new_obj->pos.y -= 200.0f; \
1580                         break; \
1581                 default : \
1582                         new_obj->pos.z -= 200.0f; \
1583                         break; \
1584                 } \
1585         } \
1586 } while(0)
1587
1588 // process cheat codes
1589 void game_process_cheats(int k)
1590 {
1591         int i;
1592         char *cryptstring;
1593
1594         if ( k == 0 ){
1595                 return;
1596         }
1597
1598         // no cheats in multiplayer, ever
1599         if(Game_mode & GM_MULTIPLAYER){
1600                 Cheats_enabled = 0;
1601                 return;
1602         }
1603
1604         k = key_to_ascii(k);
1605
1606         for (i = 0; i < CHEAT_BUFFER_LEN; i++){
1607                 CheatBuffer[i]=CheatBuffer[i+1];
1608         }
1609
1610         CheatBuffer[CHEATSPOT]=(char)k;
1611
1612         cryptstring=jcrypt(&CheatBuffer[CHEAT_BUFFER_LEN - CRYPT_STRING_LENGTH]);               
1613
1614 #ifdef FS2_DEMO 
1615         if ( !strcmp(Cheat_code_demo, cryptstring) ) {
1616                 HUD_printf(XSTR( "Cheats enabled.", 31));
1617                 Cheats_enabled = 1;
1618                 if (Player->flags & PLAYER_FLAGS_MSG_MODE){
1619                         hud_squadmsg_toggle();
1620                 }
1621         }
1622         
1623 #else
1624         if( !strcmp(Cheat_code, cryptstring) && !(Game_mode & GM_MULTIPLAYER)){
1625                 Cheats_enabled = 1;
1626                 HUD_printf("Cheats enabled");
1627         }
1628         if( !strcmp(Cheat_code_fish, cryptstring) ){
1629                 // only enable in the main hall
1630                 if((gameseq_get_state() == GS_STATE_MAIN_MENU) && (main_hall_id() == 1)){
1631                         extern void fishtank_start();
1632                         fishtank_start();
1633                 }
1634         }
1635         if( !strcmp(Cheat_code_headz, cryptstring) ){
1636                 main_hall_vasudan_funny();
1637         }
1638         if( !strcmp(Cheat_code_skip, cryptstring) && (gameseq_get_state() == GS_STATE_MAIN_MENU)){
1639                 extern void main_hall_campaign_cheat();
1640                 main_hall_campaign_cheat();
1641         }
1642         if( !strcmp(Cheat_code_tooled, cryptstring) && (Game_mode & GM_IN_MISSION)){
1643                 Tool_enabled = 1;
1644                 HUD_printf("Prepare to be taken to school");
1645         }
1646         if( !strcmp(Cheat_code_pirate, cryptstring) && (Game_mode & GM_IN_MISSION) && (Player_obj != NULL)){
1647                 HUD_printf(NOX("Walk the plank"));
1648                 
1649                 for(int idx=0; idx<1; idx++){
1650                         vector add = Player_obj->pos;
1651                         add.x += frand_range(-700.0f, 700.0f);
1652                         add.y += frand_range(-700.0f, 700.0f);
1653                         add.z += frand_range(-700.0f, 700.0f);
1654
1655                         int objnum = ship_create(&vmd_identity_matrix, &add, Num_ship_types - 1);
1656
1657                         if(objnum >= 0){
1658                                 int collided;
1659                                 ship_obj *moveup;
1660                                 object *hit_check;
1661                                 ship *s_check;
1662                                 object *new_obj = &Objects[objnum];
1663
1664                                 // place him
1665                                 // now make sure we're not colliding with anyone                
1666                                 do {
1667                                         collided = 0;
1668                                         moveup = GET_FIRST(&Ship_obj_list);
1669                                         while(moveup!=END_OF_LIST(&Ship_obj_list)){
1670                                                 // don't check the new_obj itself!!
1671                                                 if(moveup->objnum != objnum){
1672                                                         hit_check = &Objects[moveup->objnum];
1673                                                         Assert(hit_check->type == OBJ_SHIP);
1674                                                         Assert(hit_check->instance >= 0);
1675                                                         if((hit_check->type != OBJ_SHIP) || (hit_check->instance < 0)){
1676                                                                 continue;
1677                                                         }
1678                                                         s_check = &Ships[hit_check->instance];
1679                                                         
1680                                                         // just to make sure we don't get any strange magnitude errors
1681                                                         if(vm_vec_same(&hit_check->pos, &Objects[objnum].pos)){
1682                                                                 Objects[objnum].pos.x += 1.0f;
1683                                                         }
1684                                                         
1685                                                         WITHIN_BBOX();                          
1686                                                         if(collided){                                           
1687                                                                 MOVE_AWAY_BBOX();
1688                                                                 break;
1689                                                         } 
1690                                                         collided = 0;
1691                                                 }
1692                                                 moveup = GET_NEXT(moveup);
1693                                         }
1694                                 } while(collided);                                      
1695                         
1696                                 // warpin
1697                                 shipfx_warpin_start(&Objects[objnum]);
1698
1699                                 // tell him to attack                           
1700                                 // ai_add_ship_goal_player( AIG_TYPE_PLAYER_SHIP, AI_GOAL_CHASE_ANY, SM_ATTACK, NULL, &Ai_info[Ships[Objects[objnum].instance].ai_index] );
1701                         }
1702                 }
1703         }
1704 #endif
1705         /*
1706 //#ifdef INTERPLAYQA
1707         if ( !strcmp(Cheat_code_in_game, cryptstring) ) {
1708                 HUD_printf(XSTR( "Cheats enabled.", 31));
1709                 Cheats_enabled = 1;
1710                 if (Player->flags & PLAYER_FLAGS_MSG_MODE){
1711                         hud_squadmsg_toggle();
1712                 }
1713         } else if ( !strcmp(Cheat_code_movies, cryptstring) ) {
1714                 HUD_printf(XSTR( "All movies available in Tech Room", 32));
1715                 All_movies_enabled = 1;
1716                 if (Player->flags & PLAYER_FLAGS_MSG_MODE){
1717                         hud_squadmsg_toggle();
1718                 }
1719         } else if( !strcmp(Cheat_code_pirate, cryptstring) ){
1720                 HUD_printf(NOX("Walk the plank"));
1721                 
1722                 for(int idx=0; idx<1; idx++){
1723                         vector add;
1724                         add.x = frand_range(-1000.0f, 1000.0f);
1725                         add.y = frand_range(-1000.0f, 1000.0f);
1726                         add.z = frand_range(-1000.0f, 1000.0f);
1727
1728                         int objnum = ship_create(&vmd_identity_matrix, &add, Num_ship_types - 1);                       
1729
1730                         if(objnum >= 0){
1731                                 shipfx_warpin_start(&Objects[objnum]);
1732                         }
1733                 }
1734         }
1735 #endif
1736         */
1737 }
1738
1739 void game_process_keys()
1740 {
1741         int k;
1742
1743         button_info_clear(&Player->bi); // clear out the button info struct for the player
1744    do {
1745                 k = game_poll();                
1746         
1747                 // AL 12-10-97: Scan for keys used to leave the dead state      (don't process any)
1748                 // DB 1-13-98 : New popup code will run the game do state, so we must skip 
1749                 //              all key processing in this function, since everything should be run through the popup dialog
1750                 if ( Game_mode & GM_DEAD_BLEW_UP ) {
1751                         continue;
1752                 }
1753
1754                 game_process_cheats( k );
1755
1756                 // mwa -- 4/5/97 Moved these two function calls before the switch statement.  I don't think
1757                 // that this has adverse affect on anything and is acutally desireable because of the
1758                 // ESC key being used to quit any HUD message/input mode that might be currently in use
1759                 process_player_ship_keys(k);
1760
1761 //              #ifndef NDEBUG
1762                 process_debug_keys(k);          //      Note, also processed for cheats.
1763 //              #endif          
1764
1765                 switch (k) {
1766                         case 0:
1767                                 // No key
1768                                 break;
1769                         
1770                         case KEY_ESC:
1771                                 if ( Player->control_mode != PCM_NORMAL )       {
1772                                         if ( Player->control_mode == PCM_WARPOUT_STAGE1 )       {
1773                                                 gameseq_post_event( GS_EVENT_PLAYER_WARPOUT_STOP );
1774                                         } else {
1775                                                 // too late to abort warp out!
1776                                         }
1777                                 } else {
1778                                         // let the ESC key break out of messaging mode
1779                                         if ( Players[Player_num].flags & PLAYER_FLAGS_MSG_MODE ) {
1780                                                 hud_squadmsg_toggle();
1781                                                 break;
1782                                         }
1783
1784                                         // if in external view or chase view, go back to cockpit view
1785                                         if ( Viewer_mode & (VM_EXTERNAL|VM_CHASE|VM_OTHER_SHIP) ) {
1786                                                 Viewer_mode &= ~(VM_EXTERNAL|VM_CHASE|VM_OTHER_SHIP);
1787                                                 break;
1788                                         }
1789
1790                                         if (!(Game_mode & GM_DEAD_DIED))
1791                                                 game_do_end_mission_popup();
1792
1793                                 }
1794                                 break;
1795
1796                         case KEY_Y:                                                             
1797                                 break;
1798
1799                         case KEY_N:
1800                                 break;                  
1801
1802                         case KEY_ALTED + KEY_SHIFTED+KEY_J:
1803                                 // treat the current joystick position as the center position
1804                                 joy_set_cen();
1805                                 break;
1806
1807                         case KEY_DEBUGGED | KEY_PAUSE:
1808                                 gameseq_post_event( GS_EVENT_DEBUG_PAUSE_GAME );
1809                                 break;
1810
1811                         case KEY_PAUSE:
1812                                 game_process_pause_key();
1813                                 break;
1814                 } // end switch
1815         } while (k);
1816
1817         button_info_do(&Player->bi);    // call functions based on status of button_info bit vectors
1818 }
1819
1820 int button_function_critical(int n, net_player *p = NULL)
1821 {
1822         object *objp;
1823         player *pl;
1824         net_player *npl;
1825         int at_self;    // flag indicating the object is local (for hud messages, etc)
1826
1827         Assert(n >= 0);
1828    
1829         // multiplayer clients should leave critical button bits alone and pass them to the server instead
1830         if ((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER)) {
1831                 // if this flag is set, we should apply the button itself (came from the server)
1832                 if (!Multi_button_info_ok){
1833                         return 0;
1834                 }
1835         }
1836
1837         // in single player mode make sure we're using the player object and the player himself, otherwise use the object and
1838         // player pertaining to the passed net_player
1839         npl = NULL;
1840         if (p == NULL) {
1841                 objp = Player_obj;
1842                 pl = Player;
1843                 if(Game_mode & GM_MULTIPLAYER){
1844                         npl = Net_player;
1845
1846                         // if we're the server in multiplayer and we're an observer, don't process our own critical button functions
1847                         if((Net_player->flags & NETINFO_FLAG_AM_MASTER) && (Net_player->flags & NETINFO_FLAG_OBSERVER)){
1848                                 return 0;
1849                         }
1850                 }
1851                 at_self = 1;
1852         } else {
1853                 objp = &Objects[p->player->objnum];
1854                 pl = p->player;
1855                 npl = p;
1856                 at_self = 0;
1857
1858                 if ( NETPLAYER_IS_DEAD(npl) || (Ships[Objects[pl->objnum].instance].flags & SF_DYING) )
1859                         return 0;
1860         }
1861         
1862         switch (n) {                            
1863                 // cycle to next secondary weapon
1864                 case CYCLE_SECONDARY:
1865                         if(at_self)
1866                                 control_used(CYCLE_SECONDARY);
1867                         
1868                         hud_gauge_popup_start(HUD_WEAPONS_GAUGE);
1869                         if (ship_select_next_secondary(objp)) {
1870                                 ship* shipp = &Ships[objp->instance];
1871                                 if ( timestamp_elapsed(shipp->weapons.next_secondary_fire_stamp[shipp->weapons.current_secondary_bank]) ) {
1872                                         shipp->weapons.next_secondary_fire_stamp[shipp->weapons.current_secondary_bank] = timestamp(250);       //      1/4 second delay until can fire
1873                                 }
1874
1875                                 // multiplayer server should maintain bank/link status here
1876                                 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
1877                                         Assert(npl != NULL);
1878                                         multi_server_update_player_weapons(npl,shipp);                                                                          
1879                                 }                                       
1880                         }                       
1881                         break;
1882
1883                 // cycle number of missiles
1884                 case CYCLE_NUM_MISSLES:
1885                         if(at_self)
1886                                 control_used(CYCLE_NUM_MISSLES);
1887
1888                         if ( objp == Player_obj ) {
1889                                 if ( Player_ship->weapons.num_secondary_banks <= 0 ) {
1890                                         HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "This ship has no secondary weapons", 33));
1891                                         gamesnd_play_iface(SND_GENERAL_FAIL);
1892                                         break;
1893                                 }
1894                         }
1895                                         
1896                         if ( Ships[objp->instance].flags & SF_SECONDARY_DUAL_FIRE ) {           
1897                                 Ships[objp->instance].flags &= ~SF_SECONDARY_DUAL_FIRE;
1898                                 if(at_self) {
1899                                         HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Secondary weapon set to normal fire mode", 34));
1900                                         snd_play( &Snds[SND_SECONDARY_CYCLE] );
1901                                         hud_gauge_popup_start(HUD_WEAPONS_GAUGE);
1902                                 }
1903                         } else {
1904                                 Ships[objp->instance].flags |= SF_SECONDARY_DUAL_FIRE;
1905                                 if(at_self) {
1906                                         HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Secondary weapon set to dual fire mode", 35));
1907                                         snd_play( &Snds[SND_SECONDARY_CYCLE] );
1908                                         hud_gauge_popup_start(HUD_WEAPONS_GAUGE);
1909                                 }
1910                         }
1911
1912                         // multiplayer server should maintain bank/link status here
1913                         if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
1914                                 Assert(npl != NULL);
1915                                 multi_server_update_player_weapons(npl,&Ships[objp->instance]);                                                                         
1916                         }                                       
1917                         break;
1918
1919                 // increase weapon recharge rate
1920                 case INCREASE_WEAPON:
1921                         if(at_self)
1922                                 control_used(INCREASE_WEAPON);
1923                         increase_recharge_rate(objp, WEAPONS);
1924
1925                         // multiplayer server should maintain bank/link status here
1926                         if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
1927                                 Assert(npl != NULL);
1928                                 multi_server_update_player_weapons(npl,&Ships[objp->instance]);                                                                         
1929                         }                                       
1930                         break;
1931
1932                 // decrease weapon recharge rate
1933                 case DECREASE_WEAPON:
1934                         if(at_self)
1935                                 control_used(DECREASE_WEAPON);
1936                         decrease_recharge_rate(objp, WEAPONS);
1937
1938                         // multiplayer server should maintain bank/link status here
1939                         if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
1940                                 Assert(npl != NULL);
1941                                 multi_server_update_player_weapons(npl,&Ships[objp->instance]);                                                                         
1942                         }                                                               
1943                         break;
1944
1945                 // increase shield recharge rate
1946                 case INCREASE_SHIELD:
1947                         if(at_self)
1948                                 control_used(INCREASE_SHIELD);
1949                         increase_recharge_rate(objp, SHIELDS);
1950
1951                         // multiplayer server should maintain bank/link status here
1952                         if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
1953                                 Assert(npl != NULL);
1954                                 multi_server_update_player_weapons(npl,&Ships[objp->instance]);                                                                         
1955                         }                                                               
1956                         break;
1957
1958                 // decrease shield recharge rate
1959                 case DECREASE_SHIELD:
1960                         if(at_self)
1961                                 control_used(DECREASE_SHIELD);
1962                         decrease_recharge_rate(objp, SHIELDS);
1963
1964                         // multiplayer server should maintain bank/link status here
1965                         if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
1966                                 Assert(npl != NULL);
1967                                 multi_server_update_player_weapons(npl,&Ships[objp->instance]);                                                                         
1968                         }                                                               
1969                         break;
1970
1971                 // increase energy to engines
1972                 case INCREASE_ENGINE:
1973                         if(at_self)
1974                                 control_used(INCREASE_ENGINE);
1975                         increase_recharge_rate(objp, ENGINES);
1976
1977                         // multiplayer server should maintain bank/link status here
1978                         if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
1979                                 Assert(npl != NULL);
1980                                 multi_server_update_player_weapons(npl,&Ships[objp->instance]);                                                                         
1981                         }                                                       
1982                         break;
1983
1984                 // decrease energy to engines
1985                 case DECREASE_ENGINE:
1986                         if(at_self)
1987                         control_used(DECREASE_ENGINE);
1988                         decrease_recharge_rate(objp, ENGINES);
1989
1990                         // multiplayer server should maintain bank/link status here
1991                         if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
1992                                 Assert(npl != NULL);
1993                                 multi_server_update_player_weapons(npl,&Ships[objp->instance]);                                                                         
1994                         }                                                                               
1995                         break;
1996
1997                 // equalize recharge rates
1998                 case ETS_EQUALIZE:
1999                         if (at_self) {
2000                         control_used(ETS_EQUALIZE);
2001                         }
2002
2003                         set_default_recharge_rates(objp);
2004                         snd_play( &Snds[SND_ENERGY_TRANS] );
2005                         // multiplayer server should maintain bank/link status here
2006                         if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
2007                                 Assert(npl != NULL);
2008                                 multi_server_update_player_weapons(npl,&Ships[objp->instance]);                                                                         
2009                         }                                                                               
2010                         break;
2011
2012                 // equalize shield energy to all quadrants
2013                 case SHIELD_EQUALIZE:
2014                         if(at_self){
2015                                 control_used(SHIELD_EQUALIZE);
2016                         }
2017                         hud_shield_equalize(objp, pl);
2018                         break;
2019
2020                 // transfer shield energy to front
2021                 case SHIELD_XFER_TOP:
2022                         if(at_self){
2023                         control_used(SHIELD_XFER_TOP);
2024                         }
2025                         hud_augment_shield_quadrant(objp, 1);
2026                         break;
2027
2028                 // transfer shield energy to rear
2029                 case SHIELD_XFER_BOTTOM:
2030                         if(at_self)
2031                                 control_used(SHIELD_XFER_BOTTOM);
2032                         hud_augment_shield_quadrant(objp, 2);
2033                         break;
2034
2035                 // transfer shield energy to left
2036                 case SHIELD_XFER_LEFT:
2037                         if(at_self)
2038                                 control_used(SHIELD_XFER_LEFT);
2039                         hud_augment_shield_quadrant(objp, 3);
2040                         break;
2041                         
2042                 // transfer shield energy to right
2043                 case SHIELD_XFER_RIGHT:
2044                         if(at_self)
2045                                 control_used(SHIELD_XFER_RIGHT);
2046                         hud_augment_shield_quadrant(objp, 0);
2047                         break;
2048
2049                 // transfer energy to shield from weapons
2050                 case XFER_SHIELD:
2051                         if(at_self)
2052                                 control_used(XFER_SHIELD);
2053                         transfer_energy_to_shields(objp);
2054                         break;
2055
2056                 // transfer energy to weapons from shield
2057                 case XFER_LASER:
2058                         if(at_self)
2059                                 control_used(XFER_LASER);
2060                         transfer_energy_to_weapons(objp);
2061                         break;
2062
2063                 // following are not handled here, but we need to bypass the Int3()
2064                 case LAUNCH_COUNTERMEASURE:
2065                 case VIEW_SLEW:
2066                 case VIEW_EXTERNAL:
2067                 case VIEW_EXTERNAL_TOGGLE_CAMERA_LOCK:
2068                 case ONE_THIRD_THROTTLE:
2069                 case TWO_THIRDS_THROTTLE:
2070                 case MINUS_5_PERCENT_THROTTLE:
2071                 case PLUS_5_PERCENT_THROTTLE:
2072                 case ZERO_THROTTLE:
2073                 case MAX_THROTTLE:
2074                         return 0;
2075
2076                 default :
2077                         Int3(); // bad bad bad
2078                         break;
2079         }
2080
2081         return 1;
2082 }
2083
2084 // return !0 if the action is allowed, otherwise return 0
2085 int button_allowed(int n)
2086 {
2087         if ( hud_disabled() ) {
2088                 switch (n) {
2089                 case SHOW_GOALS:
2090                 case END_MISSION:
2091                 case CYCLE_NEXT_PRIMARY:
2092                 case CYCLE_PREV_PRIMARY:
2093                 case CYCLE_SECONDARY:
2094                 case ONE_THIRD_THROTTLE:
2095                 case TWO_THIRDS_THROTTLE:
2096                 case PLUS_5_PERCENT_THROTTLE:
2097                 case MINUS_5_PERCENT_THROTTLE:
2098                 case ZERO_THROTTLE:
2099                 case MAX_THROTTLE:
2100                         return 1;
2101                 default:
2102                         return 0;
2103                 }
2104         }
2105
2106         return 1;
2107 }
2108
2109 // execute function corresponding to action n
2110 // basically, these are actions which don't affect demo playback at all
2111 int button_function_demo_valid(int n)
2112 {
2113         // by default, we'll return "not processed". ret will get set to 1, if this is one of the keys which is always allowed, even in demo
2114         // playback.
2115         int ret = 0;
2116
2117         //      No keys, not even targeting keys, when player in death roll.  He can press keys after he blows up.
2118         if (Game_mode & GM_DEAD_DIED){
2119                 return 0;
2120         }
2121
2122         // any of these buttons are valid
2123         switch(n){
2124         case VIEW_CHASE:
2125                 control_used(VIEW_CHASE);
2126                 Viewer_mode ^= VM_CHASE;
2127                 if ( Viewer_mode & VM_CHASE ) {
2128                         Viewer_mode &= ~VM_EXTERNAL;
2129                 }
2130                 ret = 1;
2131                 break;
2132
2133         case VIEW_EXTERNAL:
2134                 control_used(VIEW_EXTERNAL);
2135                 Viewer_mode ^= VM_EXTERNAL;
2136                 Viewer_mode &= ~VM_EXTERNAL_CAMERA_LOCKED;      // reset camera lock when leave/entering external view
2137                 if ( Viewer_mode & VM_EXTERNAL ) {
2138                         Viewer_mode &= ~VM_CHASE;
2139                 }
2140                 ret = 1;
2141                 break;
2142
2143         case VIEW_EXTERNAL_TOGGLE_CAMERA_LOCK:
2144                 control_used(VIEW_EXTERNAL_TOGGLE_CAMERA_LOCK);
2145                 if ( Viewer_mode & VM_EXTERNAL ) {
2146                 Viewer_mode ^= VM_EXTERNAL_CAMERA_LOCKED;
2147                 if ( Viewer_mode & VM_EXTERNAL_CAMERA_LOCKED ) {
2148                         HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "External camera is locked, controls will move ship", 36));
2149                         } else {
2150                                 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "External camera is free, controls will move the camera, not the ship", 37));
2151                         }
2152                 }
2153                 ret = 1;
2154                 break;
2155
2156         case VIEW_OTHER_SHIP:
2157                 control_used(VIEW_OTHER_SHIP);
2158                 if ( Player_ai->target_objnum < 0 ) {
2159                         snd_play( &Snds[SND_TARGET_FAIL] );
2160                 } else {
2161                         if ( Objects[Player_ai->target_objnum].type != OBJ_SHIP )  {
2162                                 snd_play( &Snds[SND_TARGET_FAIL] );
2163                         } else {
2164                                 Viewer_mode ^= VM_OTHER_SHIP;
2165                         }
2166                 }
2167                 ret = 1;
2168                 break;
2169
2170         case TIME_SLOW_DOWN:
2171                 if ( Game_mode & GM_NORMAL ) {
2172                         if ( Game_time_compression > F1_0) {
2173                                 Game_time_compression /= 2;
2174                         } else {
2175                                 gamesnd_play_error_beep();
2176                         }
2177                 } else {
2178                         gamesnd_play_error_beep();
2179                 }
2180                 ret = 1;
2181                 break;
2182
2183         case TIME_SPEED_UP:
2184                 if ( Game_mode & GM_NORMAL ) {
2185                         if ( Game_time_compression < (F1_0*4) ) {
2186                                 Game_time_compression *= 2;
2187                         } else {
2188                                 gamesnd_play_error_beep();
2189                         }
2190                 } else {
2191                         gamesnd_play_error_beep();
2192                 }
2193                 ret = 1;
2194                 break;
2195         }
2196
2197         // done
2198         return ret;
2199 }
2200
2201 // execute function corresponding to action n (BUTTON_ #define from KeyControl.h)
2202 int button_function(int n)
2203 {
2204         Assert(n >= 0);
2205
2206         if ( !button_allowed(n) ) {
2207                 return 0;
2208         }
2209
2210         //      No keys, not even targeting keys, when player in death roll.  He can press keys after he blows up.
2211         if (Game_mode & GM_DEAD_DIED){
2212                 return 0;
2213         }
2214                 
2215         switch (n) {
2216                 // cycle to next primary weapon
2217                 case CYCLE_NEXT_PRIMARY:                        
2218                         // bogus?
2219                         if((Player_obj == NULL) || (Player_ship == NULL)){
2220                                 break;
2221                         }
2222
2223                         hud_gauge_popup_start(HUD_WEAPONS_GAUGE);
2224                         if (ship_select_next_primary(Player_obj, CYCLE_PRIMARY_NEXT)) {
2225                                 ship* shipp = Player_ship;
2226                                 shipp->weapons.next_primary_fire_stamp[shipp->weapons.current_primary_bank] = timestamp(250);   //      1/4 second delay until can fire                         
2227                                 // multiplayer server should maintain bank/link status here
2228                                 // if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
2229 //                                      Assert(npl != NULL);
2230 //                                      multi_server_update_player_weapons(npl,shipp);                                                                          
2231 //                              }                                       
2232                         }                       
2233                         break;
2234
2235                 // cycle to previous primary weapon
2236                 case CYCLE_PREV_PRIMARY:                        
2237                         // bogus?
2238                         if((Player_obj == NULL) || (Player_ship == NULL)){
2239                                 break;
2240                         }
2241
2242                         hud_gauge_popup_start(HUD_WEAPONS_GAUGE);
2243                         if (ship_select_next_primary(Player_obj, CYCLE_PRIMARY_PREV)) {
2244                                 ship* shipp = Player_ship;
2245                                 shipp->weapons.next_primary_fire_stamp[shipp->weapons.current_primary_bank] = timestamp(250);   //      1/4 second delay until can fire
2246
2247                                 // multiplayer server should maintain bank/link status here
2248                                 // if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
2249                                         // Assert(npl != NULL);
2250                                         // multi_server_update_player_weapons(npl,shipp);                                                                               
2251                                 // }                                    
2252                         }                       
2253                         break;
2254
2255                 // cycle to next secondary weapon
2256                 case CYCLE_SECONDARY:
2257                         return button_function_critical(CYCLE_SECONDARY);
2258                         break;
2259
2260                 // cycle number of missiles fired from secondary bank
2261                 case CYCLE_NUM_MISSLES:
2262          return button_function_critical(CYCLE_NUM_MISSLES);                    
2263                         break;
2264
2265                 // undefined in multiplayer for clients right now
2266                 // match target speed
2267                 case MATCH_TARGET_SPEED:                        
2268                         control_used(MATCH_TARGET_SPEED);
2269                         // If player is auto-matching, break auto-match speed
2270                         if ( Player->flags & PLAYER_FLAGS_AUTO_MATCH_SPEED ) {
2271                                 Player->flags &= ~PLAYER_FLAGS_AUTO_MATCH_SPEED;
2272                         }
2273                         player_match_target_speed();                                            
2274                         break;
2275
2276                 // undefined in multiplayer for clients right now
2277                 // toggle auto-match target speed
2278                 case TOGGLE_AUTO_MATCH_TARGET_SPEED:
2279                         // multiplayer observers can't match target speed
2280                         if((Game_mode & GM_MULTIPLAYER) && (Net_player != NULL) && ((Net_player->flags & NETINFO_FLAG_OBSERVER) || (Player_obj->type == OBJ_OBSERVER)) ){
2281                                 break;
2282                         }
2283         
2284                         Player->flags ^= PLAYER_FLAGS_AUTO_MATCH_SPEED;                 
2285                         control_used(TOGGLE_AUTO_MATCH_TARGET_SPEED);
2286                         hud_gauge_popup_start(HUD_AUTO_SPEED);
2287                         if ( Players[Player_num].flags & PLAYER_FLAGS_AUTO_MATCH_SPEED ) {
2288                                 snd_play(&Snds[SND_SHIELD_XFER_OK], 1.0f);
2289 //                              HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Auto match target speed activated", -1));
2290                                 if ( !Player->flags & PLAYER_FLAGS_MATCH_TARGET ) {
2291                                         player_match_target_speed();
2292                                 }
2293                         }
2294                         else {
2295 //                              HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Auto match target deactivated", -1));
2296                                 snd_play(&Snds[SND_SHIELD_XFER_OK], 1.0f);
2297                                 player_match_target_speed();
2298                         }                       
2299                         break;
2300
2301                 // target next
2302                 case TARGET_NEXT:
2303                         control_used(TARGET_NEXT);                      
2304                         if ( hud_sensors_ok(Player_ship) ) {
2305                                 hud_target_next();
2306                         }
2307                         break;
2308
2309                 // target previous
2310                 case TARGET_PREV:
2311                         control_used(TARGET_PREV);                      
2312                         if ( hud_sensors_ok(Player_ship) ) {
2313                                 hud_target_prev();                      
2314                         }
2315                         break;
2316
2317                 // target the next hostile target
2318                 case TARGET_NEXT_CLOSEST_HOSTILE:
2319                         control_used(TARGET_NEXT_CLOSEST_HOSTILE);                      
2320                         if (hud_sensors_ok(Player_ship)){
2321                                 hud_target_next_list();
2322                         }                       
2323                         break;
2324
2325                 // target the previous closest hostile 
2326                 case TARGET_PREV_CLOSEST_HOSTILE:
2327                         control_used(TARGET_PREV_CLOSEST_HOSTILE);                      
2328                         if (hud_sensors_ok(Player_ship)){
2329                                 hud_target_next_list(1,0);
2330                         }
2331                         break;
2332
2333                 // toggle auto-targeting
2334                 case TOGGLE_AUTO_TARGETING:
2335                         control_used(TOGGLE_AUTO_TARGETING);
2336                         hud_gauge_popup_start(HUD_AUTO_TARGET);
2337                         Players[Player_num].flags ^= PLAYER_FLAGS_AUTO_TARGETING;
2338                         if ( Players[Player_num].flags & PLAYER_FLAGS_AUTO_TARGETING ) {
2339                                 if (hud_sensors_ok(Player_ship)) {
2340                                         hud_target_closest(opposing_team_mask(Player_ship->team), -1, FALSE, TRUE );
2341                                         snd_play(&Snds[SND_SHIELD_XFER_OK], 1.0f);
2342 //                                      HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Auto targeting activated", -1));
2343                                 } else {
2344                                         Players[Player_num].flags ^= PLAYER_FLAGS_AUTO_TARGETING;
2345                                 }
2346                         } else {
2347                                 snd_play(&Snds[SND_SHIELD_XFER_OK], 1.0f);
2348 //                              HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Auto targeting deactivated", -1));
2349                         }
2350                         break;
2351
2352                 // target the next friendly ship
2353                 case TARGET_NEXT_CLOSEST_FRIENDLY:
2354                         control_used(TARGET_NEXT_CLOSEST_FRIENDLY);                     
2355                         if (hud_sensors_ok(Player_ship)){
2356                                 hud_target_next_list(0);
2357                         }
2358                         break;
2359
2360                 // target the closest friendly ship
2361                 case TARGET_PREV_CLOSEST_FRIENDLY:
2362                         control_used(TARGET_PREV_CLOSEST_FRIENDLY);                     
2363                         if (hud_sensors_ok(Player_ship)) {
2364                                 hud_target_next_list(0,0);
2365                         }
2366                         break;
2367
2368                 // target ship closest to center of reticle
2369                 case TARGET_SHIP_IN_RETICLE:
2370                         control_used(TARGET_SHIP_IN_RETICLE);                   
2371                         if (hud_sensors_ok(Player_ship)){
2372                                 hud_target_in_reticle_new();
2373                         }
2374                         break;
2375
2376                 case TARGET_LAST_TRANMISSION_SENDER:
2377                         control_used(TARGET_LAST_TRANMISSION_SENDER);
2378                         if ( hud_sensors_ok(Player_ship)) {
2379                                 hud_target_last_transmit();
2380                         }
2381                         break;
2382
2383                 // target the closest repair ship
2384                 case TARGET_CLOSEST_REPAIR_SHIP:
2385                         control_used(TARGET_CLOSEST_REPAIR_SHIP);
2386                         // AL: Try to find the closest repair ship coming to repair the player... if no support
2387                         //               ships are coming to rearm the player, just try for the closest repair ship
2388                         if ( hud_target_closest_repair_ship(OBJ_INDEX(Player_obj)) == 0 ) {
2389                                 if ( hud_target_closest_repair_ship() == 0 ) {
2390                                         snd_play(&Snds[SND_TARGET_FAIL]);
2391                                 }
2392                         }
2393                         break;
2394
2395                 // target the closest ship attacking current target
2396                 case TARGET_CLOSEST_SHIP_ATTACKING_TARGET:
2397                         control_used(TARGET_CLOSEST_SHIP_ATTACKING_TARGET);
2398                         if (hud_sensors_ok(Player_ship)){
2399                                 hud_target_closest(opposing_team_mask(Player_ship->team), Player_ai->target_objnum);
2400                         }
2401                         break;
2402
2403                 // stop targeting ship
2404                 case STOP_TARGETING_SHIP:
2405                         control_used(STOP_TARGETING_SHIP);
2406                         hud_cease_targeting();
2407                         break;
2408
2409                 // target closest ship that is attacking player
2410                 case TARGET_CLOSEST_SHIP_ATTACKING_SELF:
2411                         control_used(TARGET_CLOSEST_SHIP_ATTACKING_SELF);
2412                         if (hud_sensors_ok(Player_ship)){
2413                                 hud_target_closest(opposing_team_mask(Player_ship->team), OBJ_INDEX(Player_obj), TRUE, 0, 1);
2414                         }
2415                         break;
2416
2417                 // target your target's target
2418                 case TARGET_TARGETS_TARGET:
2419                         control_used(TARGET_TARGETS_TARGET);
2420                         if (hud_sensors_ok(Player_ship)){
2421                                 hud_target_targets_target();
2422                         }
2423                         break;
2424
2425                 // target ships subsystem in reticle
2426                 case TARGET_SUBOBJECT_IN_RETICLE:
2427                         control_used(TARGET_SUBOBJECT_IN_RETICLE);
2428                         if (hud_sensors_ok(Player_ship)){
2429                                 hud_target_subsystem_in_reticle();
2430                         }
2431                         break;
2432
2433                 case TARGET_PREV_SUBOBJECT:
2434                         control_used(TARGET_PREV_SUBOBJECT);
2435                         if (hud_sensors_ok(Player_ship)){
2436                                 hud_target_prev_subobject();
2437                         }
2438                         break;
2439
2440                 // target next subsystem on current target
2441                 case TARGET_NEXT_SUBOBJECT:
2442                         control_used(TARGET_NEXT_SUBOBJECT);
2443                         if (hud_sensors_ok(Player_ship)){
2444                                 hud_target_next_subobject();
2445                         }
2446                         break;
2447
2448                 // stop targeting subsystems on ship
2449                 case STOP_TARGETING_SUBSYSTEM:
2450                         control_used(STOP_TARGETING_SUBSYSTEM);
2451                         hud_cease_subsystem_targeting();
2452                         break;
2453                         
2454                 case TARGET_NEXT_BOMB:
2455                         control_used(TARGET_NEXT_BOMB);
2456                         hud_target_missile(Player_obj, 1);
2457                         break;
2458
2459                 case TARGET_PREV_BOMB:
2460                         control_used(TARGET_PREV_BOMB);
2461                         hud_target_missile(Player_obj, 0);
2462                         break;
2463
2464                 case TARGET_NEXT_UNINSPECTED_CARGO:
2465                         hud_target_uninspected_object(1);
2466                         break;
2467
2468                 case TARGET_PREV_UNINSPECTED_CARGO:
2469                         hud_target_uninspected_object(0);
2470                         break;
2471
2472                 case TARGET_NEWEST_SHIP:
2473                         hud_target_newest_ship();
2474                         break;
2475
2476                 case TARGET_NEXT_LIVE_TURRET:
2477                         hud_target_live_turret(1);
2478                         break;
2479
2480                 case TARGET_PREV_LIVE_TURRET:
2481                         hud_target_live_turret(0);
2482                         break;
2483
2484                 // wingman message: attack current target
2485                 case ATTACK_MESSAGE:
2486                         control_used(ATTACK_MESSAGE);
2487                         hud_squadmsg_shortcut( ATTACK_TARGET_ITEM );
2488                         break;
2489
2490                 // wingman message: disarm current target
2491                 case DISARM_MESSAGE:
2492                         control_used(DISARM_MESSAGE);
2493                         hud_squadmsg_shortcut( DISARM_TARGET_ITEM );
2494                         break;
2495
2496                 // wingman message: disable current target
2497                 case DISABLE_MESSAGE:
2498                         control_used(DISABLE_MESSAGE);
2499                         hud_squadmsg_shortcut( DISABLE_TARGET_ITEM );
2500                         break;
2501
2502                 // wingman message: disable current target
2503                 case ATTACK_SUBSYSTEM_MESSAGE:
2504                         control_used(ATTACK_SUBSYSTEM_MESSAGE);
2505                         hud_squadmsg_shortcut( DISABLE_SUBSYSTEM_ITEM );
2506                         break;
2507
2508                 // wingman message: capture current target
2509                 case CAPTURE_MESSAGE:
2510                         control_used(CAPTURE_MESSAGE);
2511                         hud_squadmsg_shortcut( CAPTURE_TARGET_ITEM );
2512                         break;
2513
2514                 // wingman message: engage enemy
2515                 case ENGAGE_MESSAGE:
2516                 control_used(ENGAGE_MESSAGE);
2517                         hud_squadmsg_shortcut( ENGAGE_ENEMY_ITEM );
2518                         break;
2519
2520                 // wingman message: form on my wing
2521                 case FORM_MESSAGE:
2522                         control_used(FORM_MESSAGE);
2523                         hud_squadmsg_shortcut( FORMATION_ITEM );
2524                         break;
2525
2526                 // wingman message: protect current target
2527                 case PROTECT_MESSAGE:
2528                         control_used(PROTECT_MESSAGE);
2529                         hud_squadmsg_shortcut( PROTECT_TARGET_ITEM );
2530                         break;
2531
2532                 // wingman message: cover me
2533                 case COVER_MESSAGE:
2534                         control_used(COVER_MESSAGE);
2535                         hud_squadmsg_shortcut( COVER_ME_ITEM );
2536                         break;
2537                 
2538                 // wingman message: warp out
2539                 case WARP_MESSAGE:
2540                         control_used(WARP_MESSAGE);
2541                         hud_squadmsg_shortcut( DEPART_ITEM );
2542                         break;
2543
2544                 case IGNORE_MESSAGE:
2545                         control_used(IGNORE_MESSAGE);
2546                         hud_squadmsg_shortcut( IGNORE_TARGET_ITEM );
2547                         break;
2548
2549                 // rearm message
2550                 case REARM_MESSAGE:
2551                         control_used(REARM_MESSAGE);
2552                         hud_squadmsg_rearm_shortcut();
2553                         break;
2554
2555                 // cycle to next radar range
2556                 case RADAR_RANGE_CYCLE:
2557                         control_used(RADAR_RANGE_CYCLE);
2558                         HUD_config.rp_dist++;
2559                         if ( HUD_config.rp_dist >= RR_MAX_RANGES )
2560                                 HUD_config.rp_dist = 0;
2561
2562                         HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Radar range set to %s", 38), Radar_range_text(HUD_config.rp_dist));
2563                         break;
2564
2565                 // toggle the squadmate messaging menu
2566                 case SQUADMSG_MENU:
2567                         control_used(SQUADMSG_MENU);
2568                         hud_squadmsg_toggle();                          // leave the details to the messaging code!!!
2569                         break;
2570
2571                 // show the mission goals screen
2572                 case SHOW_GOALS:
2573                         control_used(SHOW_GOALS);
2574                         gameseq_post_event( GS_EVENT_SHOW_GOALS );
2575                         break;
2576
2577                 // end the mission
2578                 case END_MISSION:
2579                         // in multiplayer, all end mission requests should go through the server
2580                         if(Game_mode & GM_MULTIPLAYER){                         
2581                                 multi_handle_end_mission_request();
2582                                 break;
2583                         }
2584
2585                         control_used(END_MISSION);
2586                         
2587                         if (collide_predict_large_ship(Player_obj, 200.0f)) {
2588                                 gamesnd_play_iface(SND_GENERAL_FAIL);
2589                                 HUD_printf(XSTR( "** WARNING ** Collision danger.  Warpout not activated.", 39));
2590                         } else if (ship_get_subsystem_strength( Player_ship, SUBSYSTEM_ENGINE ) < 0.1f) {
2591                                 gamesnd_play_iface(SND_GENERAL_FAIL);
2592                                 HUD_printf(XSTR( "Engine failure.  Cannot engage warp drive.", 40));
2593                         } else {
2594                                 gameseq_post_event( GS_EVENT_PLAYER_WARPOUT_START );
2595                         }                       
2596                         break;
2597
2598                 case ADD_REMOVE_ESCORT:
2599                         if ( Player_ai->target_objnum >= 0 ) {
2600                                 control_used(ADD_REMOVE_ESCORT);
2601                                 hud_add_remove_ship_escort(Player_ai->target_objnum);
2602                         }
2603                         break;
2604
2605                 case ESCORT_CLEAR:
2606                         control_used(ESCORT_CLEAR);
2607                         hud_escort_clear_all();
2608                         break;
2609
2610                 case TARGET_NEXT_ESCORT_SHIP:
2611                         control_used(TARGET_NEXT_ESCORT_SHIP);
2612                         hud_escort_target_next();
2613                         break;
2614
2615                 // increase weapon recharge rate
2616                 case INCREASE_WEAPON:
2617                         hud_gauge_popup_start(HUD_ETS_GAUGE);
2618                         return button_function_critical(INCREASE_WEAPON);
2619                         break;
2620
2621                 // decrease weapon recharge rate
2622                 case DECREASE_WEAPON:
2623                         hud_gauge_popup_start(HUD_ETS_GAUGE);
2624                         return button_function_critical(DECREASE_WEAPON);
2625                         break;
2626
2627                 // increase shield recharge rate
2628                 case INCREASE_SHIELD:
2629                         hud_gauge_popup_start(HUD_ETS_GAUGE);
2630                         return button_function_critical(INCREASE_SHIELD);
2631                         break;
2632
2633                 // decrease shield recharge rate
2634                 case DECREASE_SHIELD:
2635                         hud_gauge_popup_start(HUD_ETS_GAUGE);
2636                         return button_function_critical(DECREASE_SHIELD);
2637                         break;
2638
2639                 // increase energy to engines
2640                 case INCREASE_ENGINE:
2641                         hud_gauge_popup_start(HUD_ETS_GAUGE);
2642                         return button_function_critical(INCREASE_ENGINE);
2643                         break;
2644
2645                 // decrease energy to engines
2646                 case DECREASE_ENGINE:
2647                         hud_gauge_popup_start(HUD_ETS_GAUGE);
2648                         return button_function_critical(DECREASE_ENGINE);
2649                         break;
2650
2651                 case ETS_EQUALIZE:
2652                         hud_gauge_popup_start(HUD_ETS_GAUGE);
2653                         return button_function_critical(ETS_EQUALIZE);
2654                         break;
2655
2656                 // equalize shield energy to all quadrants
2657                 case SHIELD_EQUALIZE:
2658                         return button_function_critical(SHIELD_EQUALIZE);
2659                         break;
2660
2661                 // transfer shield energy to front
2662                 case SHIELD_XFER_TOP:
2663          return button_function_critical(SHIELD_XFER_TOP);
2664                         break;
2665
2666                 // transfer shield energy to rear
2667                 case SHIELD_XFER_BOTTOM:
2668                         return button_function_critical(SHIELD_XFER_BOTTOM);
2669                         break;
2670
2671                 // transfer shield energy to left
2672                 case SHIELD_XFER_LEFT:
2673                         return button_function_critical(SHIELD_XFER_LEFT);
2674                         break;
2675                 
2676                 // transfer shield energy to right
2677                 case SHIELD_XFER_RIGHT:
2678                         return button_function_critical(SHIELD_XFER_RIGHT);
2679                         break;
2680
2681                 // transfer energy to shield from weapons
2682                 case XFER_SHIELD:
2683                         return button_function_critical(XFER_SHIELD);
2684                         break;
2685
2686                 // transfer energy to weapons from shield
2687                 case XFER_LASER:
2688                         return button_function_critical(XFER_LASER);
2689                         break;
2690
2691                 // message all netplayers button
2692                 case MULTI_MESSAGE_ALL:
2693                         multi_msg_key_down(MULTI_MSG_ALL);
2694                         break;
2695
2696                 // message all friendlies button
2697                 case MULTI_MESSAGE_FRIENDLY:
2698                         multi_msg_key_down(MULTI_MSG_FRIENDLY);
2699                         break;
2700
2701                 // message all hostiles button
2702                 case MULTI_MESSAGE_HOSTILE:
2703                         multi_msg_key_down(MULTI_MSG_HOSTILE);
2704                         break;
2705
2706                 // message targeted ship (if player)
2707                 case MULTI_MESSAGE_TARGET:
2708                         multi_msg_key_down(MULTI_MSG_TARGET);
2709                         break;
2710
2711                 // if i'm an observer, zoom to my targeted object
2712                 case MULTI_OBSERVER_ZOOM_TO:
2713                         multi_obs_zoom_to_target();
2714                         break;          
2715
2716                 // toggle between high and low HUD contrast
2717                 case TOGGLE_HUD_CONTRAST:
2718                         gamesnd_play_iface(SND_USER_SELECT);
2719                         hud_toggle_contrast();
2720                         break;
2721
2722                 // toggle network info
2723                 case MULTI_TOGGLE_NETINFO:
2724                         extern int Multi_display_netinfo;
2725                         Multi_display_netinfo = !Multi_display_netinfo;
2726                         break;
2727
2728                 // self destruct (multiplayer only)
2729                 case MULTI_SELF_DESTRUCT:
2730                         if(!(Game_mode & GM_MULTIPLAYER)){
2731                                 break;
2732                         }
2733
2734                         // bogus netplayer
2735                         if((Net_player == NULL) || (Net_player->player == NULL)){
2736                                 break;
2737                         }
2738
2739                         // blow myself up, if I'm the server
2740                         if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
2741                                 if((Net_player->player->objnum >= 0) && (Net_player->player->objnum < MAX_OBJECTS) && 
2742                                         (Objects[Net_player->player->objnum].type == OBJ_SHIP) && (Objects[Net_player->player->objnum].instance >= 0) && (Objects[Net_player->player->objnum].instance < MAX_SHIPS)){
2743
2744                                         ship_self_destruct(&Objects[Net_player->player->objnum]);
2745                                 }
2746                         }
2747                         // otherwise send a packet to the server
2748                         else {
2749                                 send_self_destruct_packet();
2750                         }
2751                         break;
2752
2753                 // following are not handled here, but we need to bypass the Int3()
2754                 case LAUNCH_COUNTERMEASURE:
2755                 case VIEW_SLEW:
2756                 case ONE_THIRD_THROTTLE:
2757                 case TWO_THIRDS_THROTTLE:
2758                 case MINUS_5_PERCENT_THROTTLE:
2759                 case PLUS_5_PERCENT_THROTTLE:
2760                 case ZERO_THROTTLE:
2761                 case MAX_THROTTLE:
2762                         return 0;
2763
2764                 default:
2765                         Int3();
2766                         break;
2767         } // end switch
2768
2769         return 1;
2770 }
2771
2772 // Call functions for when buttons are pressed
2773 void button_info_do(button_info *bi)
2774 {
2775         int i, j;
2776
2777         for (i=0; i<NUM_BUTTON_FIELDS; i++) {
2778                 if ( bi->status[i] == 0 ){
2779                         continue;
2780                 }
2781
2782                 // at least one bit is set in the status integer
2783                 for (j=0; j<32; j++) {
2784
2785                         // check if the bit is set. If button_function returns 1 (implying the action was taken), then unset the bit
2786                         if ( bi->status[i] & (1 << j) ) {
2787                                 // always process buttons which are valid for demo playback
2788                                 if(button_function_demo_valid(32 * i + j)){
2789                                         bi->status[i] &= ~(1 << j);
2790                                 }
2791                                 // other buttons
2792                                 else {
2793                                         // if we're in demo playback, always clear the bits
2794                                         if(Game_mode & GM_DEMO_PLAYBACK){
2795                                                 bi->status[i] &= ~(1 << j);
2796                                         }
2797                                         // otherwise check as normal
2798                                         else if (button_function(32 * i + j)) {
2799                                                 bi->status[i] &= ~(1 << j);                                     
2800                                         }
2801                                 }
2802                         }
2803                 }
2804         }
2805 }
2806
2807
2808 // set the bit for the corresponding action n (BUTTON_ #define from KeyControl.h)
2809 void button_info_set(button_info *bi, int n)
2810 {
2811         int field_num, bit_num;
2812         
2813         field_num = n / 32;
2814         bit_num = n % 32;
2815
2816         bi->status[field_num] |= (1 << bit_num);        
2817 }
2818
2819 // unset the bit for the corresponding action n (BUTTON_ #define from KeyControl.h)
2820 void button_info_unset(button_info *bi, int n)
2821 {
2822         int field_num, bit_num;
2823         
2824         field_num = n / 32;
2825         bit_num = n % 32;
2826
2827         bi->status[field_num] &= ~(1 << bit_num);       
2828 }
2829
2830 int button_info_query(button_info *bi, int n)
2831 {
2832         return bi->status[n / 32] & (1 << (n % 32));
2833 }
2834
2835 // clear out the button_info struct
2836 void button_info_clear(button_info *bi)
2837 {
2838         int i;
2839
2840         for (i=0; i<NUM_BUTTON_FIELDS; i++) {
2841                 bi->status[i] = 0;
2842         }
2843 }
2844
2845 // strip out all noncritical keys from the button info struct
2846 void button_strip_noncritical_keys(button_info *bi)
2847 {
2848         int idx;
2849
2850         // clear out all noncritical keys
2851         for(idx=0;idx<Non_critical_key_set_size;idx++){
2852                 button_info_unset(bi,Non_critical_key_set[idx]);
2853         }
2854
2855
2856