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