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