2 * Copyright (C) Volition, Inc. 1999. All rights reserved.
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
10 * $Logfile: /Freespace2/code/Io/KeyControl.cpp $
15 * Routines to read and deal with keyboard input.
18 * Revision 1.5 2003/05/25 02:30:42 taylor
21 * Revision 1.4 2002/07/28 05:05:08 relnev
22 * removed some old stuff
24 * Revision 1.3 2002/06/18 08:58:53 relnev
25 * last few struct changes
27 * Revision 1.2 2002/06/09 04:41:21 relnev
28 * added copyright header
30 * Revision 1.1.1.1 2002/05/03 03:28:09 root
34 * 47 9/09/99 11:40p Dave
35 * Handle an SDL_assert() in beam code. Added supernova sounds. Play the right
36 * 2 end movies properly, based upon what the player did in the mission.
38 * 46 9/07/99 11:26p Andsager
39 * Fix "r" targeting key, making evaluate_ship_as_closest_target() and
40 * hud_target_live_turret() consider if turret is targeting player
42 * 45 9/03/99 1:31a Dave
43 * CD checking by act. Added support to play 2 cutscenes in a row
44 * seamlessly. Fixed super low level cfile bug related to files in the
45 * root directory of a CD. Added cheat code to set campaign mission # in
48 * 44 9/01/99 10:09a Dave
51 * 43 8/27/99 10:36a Dave
52 * Impose a 2% penalty for hitting the shield balance key.
54 * 42 8/27/99 9:57a Dave
55 * Enabled standard cheat codes. Allow player to continue in a campaing
56 * after using cheat codes.
58 * 41 8/26/99 9:45a Dave
59 * First pass at easter eggs and cheats.
61 * 40 8/24/99 1:49a Dave
62 * Fixed client-side afterburner stuttering. Added checkbox for no version
63 * checking on PXO join. Made button info passing more friendly between
66 * 39 8/22/99 5:53p Dave
67 * Scoring fixes. Added self destruct key. Put callsigns in the logfile
68 * instead of ship designations for multiplayer players.
70 * 38 8/19/99 10:59a Dave
71 * Packet loss detection.
73 * 37 8/18/99 12:09p Andsager
74 * Add debug if message has no anim for message. Make messages come from
77 * 36 8/05/99 2:05a Dave
80 * 35 8/01/99 12:39p Dave
81 * Added HUD contrast control key (for nebula).
83 * 34 7/31/99 2:30p Dave
84 * Added nifty mission message debug viewing keys.
86 * 33 7/21/99 8:10p Dave
87 * First run of supernova effect.
89 * 32 7/15/99 4:09p Andsager
90 * Disable cheats for FS2_DEMO
92 * 31 7/15/99 9:20a Andsager
93 * FS2_DEMO initial checkin
95 * 30 7/07/99 3:32p Dave
96 * Oops. Forgot to remove this.
98 * 29 7/02/99 4:31p Dave
99 * Much more sophisticated lightning support.
101 * 28 6/10/99 3:43p Dave
102 * Do a better job of syncing text colors to HUD gauges.
104 * 27 6/09/99 2:55p Andsager
105 * Allow multiple asteroid subtypes (of large, medium, small) and follow
108 * 26 5/24/99 5:45p Dave
109 * Added detail levels to the nebula, with a decent speedup. Split nebula
110 * lightning into its own section.
112 * 25 5/08/99 8:25p Dave
113 * Upped object pairs. First run of nebula lightning.
115 * 24 5/05/99 9:02p Dave
116 * Fixed D3D aabitmap rendering. Spiffed up nebula effect a bit (added
117 * rotations, tweaked values, made bitmap selection more random). Fixed
118 * D3D beam weapon clipping problem. Added D3d frame dumping.
120 * 23 5/03/99 9:07a Dave
121 * Pirate Bob. Changed beam test code a bit.
123 * 22 4/21/99 6:15p Dave
124 * Did some serious housecleaning in the beam code. Made it ready to go
125 * for anti-fighter "pulse" weapons. Fixed collision pair creation. Added
126 * a handy macro for recalculating collision pairs for a given object.
128 * 21 4/16/99 5:54p Dave
129 * Support for on/off style "stream" weapons. Real early support for
130 * target-painting lasers.
132 * 20 3/31/99 8:24p Dave
133 * Beefed up all kinds of stuff, incluging beam weapons, nebula effects
134 * and background nebulae. Added per-ship non-dimming pixel colors.
136 * 19 3/29/99 6:17p Dave
137 * More work on demo system. Got just about everything in except for
138 * blowing ships up, secondary weapons and player death/warpout.
140 * 18 3/28/99 5:58p Dave
141 * Added early demo code. Make objects move. Nice and framerate
142 * independant, but not much else. Don't use yet unless you're me :)
144 * 17 3/09/99 6:24p Dave
145 * More work on object update revamping. Identified several sources of
146 * unnecessary bandwidth.
148 * 16 2/21/99 6:01p Dave
149 * Fixed standalone WSS packets.
151 * 15 2/21/99 1:48p Dave
152 * Some code for monitoring datarate for multiplayer in detail.
154 * 14 1/21/99 2:06p Dave
155 * Final checkin for multiplayer testing.
157 * 13 1/19/99 3:57p Andsager
158 * Round 2 of variables
160 * 12 1/12/99 12:53a Dave
161 * More work on beam weapons - made collision detection very efficient -
162 * collide against all object types properly - made 3 movement types
163 * smooth. Put in test code to check for possible non-darkening pixels on
166 * 11 1/08/99 2:08p Dave
167 * Fixed software rendering for pofview. Super early support for AWACS and
170 * 10 12/06/98 2:36p Dave
171 * Drastically improved nebula fogging.
173 * 9 12/04/98 3:37p Andsager
174 * Added comment out asteroid launcher
176 * 8 11/19/98 4:19p Dave
177 * Put IPX sockets back in psnet. Consolidated all multiplayer config
180 * 7 11/05/98 5:55p Dave
181 * Big pass at reducing #includes
183 * 6 10/26/98 9:42a Dave
184 * Early flak gun support.
186 * 5 10/20/98 1:39p Andsager
187 * Make so sparks follow animated ship submodels. Modify
188 * ship_weapon_do_hit_stuff() and ship_apply_local_damage() to add
189 * submodel_num. Add submodel_num to multiplayer hit packet.
191 * 4 10/13/98 9:28a Dave
192 * Started neatening up freespace.h. Many variables renamed and
193 * reorganized. Added AlphaColors.[h,cpp]
195 * 3 10/09/98 2:57p Dave
196 * Starting splitting up OS stuff.
198 * 2 10/07/98 10:53a Dave
201 * 1 10/07/98 10:49a Dave
203 * 387 6/17/98 11:02a Lawrance
204 * show what cheat code is in the comment
206 * 386 6/09/98 5:15p Lawrance
207 * French/German localization
209 * 385 6/09/98 10:31a Hoffoss
210 * Created index numbers for all xstr() references. Any new xstr() stuff
211 * added from here on out should be added to the end if the list. The
212 * current list count can be found in FreeSpace.cpp (search for
215 * 384 6/01/98 11:43a John
216 * JAS & MK: Classified all strings for localization.
218 * 383 5/24/98 1:46p Mike
221 * 382 5/19/98 2:20p Mike
222 * Comment out nprintf().
224 * 381 5/19/98 12:19p Mike
227 * 380 5/19/98 11:11a Lawrance
228 * Make 'G' only target hostiles
230 * 379 5/18/98 11:00p Mike
231 * Adding support for cheat system.
233 * 378 5/18/98 12:41a Allender
234 * fixed subsystem problems on clients (i.e. not reporting properly on
235 * damage indicator). Fixed ingame join problem with respawns. minor
238 * 377 5/17/98 1:43a Dave
239 * Eradicated chatbox problems. Remove speed match for observers. Put in
240 * help screens for PXO. Fix messaging and end mission privelges. Fixed
241 * team select screen bugs. Misc UI fixes.
243 * 376 5/15/98 8:36p Lawrance
244 * Add 'target ship that last sent transmission' target key
246 * 375 5/14/98 11:07a Lawrance
247 * Ensure looped sounds get stopped before stopping all channels
249 * 374 5/12/98 11:59p Dave
250 * Put in some more functionality for Parallax Online.
252 * 373 5/11/98 5:29p Hoffoss
253 * Added mouse button mapped to joystick button support.
255 * 372 5/08/98 10:14a Lawrance
256 * Play sound when auto-targeting gets toggled.
258 * 371 5/04/98 9:25a Allender
259 * don't allow time compression in multiplayer
261 * 370 4/30/98 4:43p Allender
262 * trap player obj when changing dual fire status on ship
264 * 369 4/30/98 4:16p Peter
265 * fixes for critical button functions when a player (client) ship is dead
268 * 368 4/27/98 9:03a Dave
269 * Fixed a multiplayer sequencing bug where paused players who were in the
270 * options screen got an SDL_assert when unpausing. Removed an optimiized
271 * build warning in keycontrol.
273 * 367 4/26/98 4:29p Lawrance
274 * Put back time compression keys... somehow they were trashed by a later
277 * 366 4/25/98 5:36p Mike
278 * Prevent player warpout if engine < 10%.
284 #include "linklist.h"
292 #include "contexthelp.h"
293 #include "gamesequence.h"
295 #include "missiongoals.h"
297 #include "hudtarget.h"
298 #include "optionsmenu.h"
299 #include "freespace.h"
300 #include "controlsconfig.h"
304 #include "multiutil.h"
308 #include "hudsquadmsg.h"
309 #include "eventmusic.h"
310 #include "animplay.h"
311 #include "freespace.h"
312 #include "cmeasure.h"
313 #include "missionhotkey.h"
314 #include "afterburner.h"
315 #include "missionparse.h"
316 #include "hudescort.h"
317 #include "hudshield.h"
318 #include "multiutil.h"
319 #include "multimsgs.h"
320 #include "keycontrol.h"
324 #include "hudobserver.h"
325 #include "missionlog.h"
326 #include "hudtargetbox.h"
328 #include "objcollide.h"
329 #include "hudconfig.h"
330 #include "missioncampaign.h"
332 #include "multi_respawn.h"
333 #include "multi_pmsg.h"
336 #include "multi_pause.h"
337 #include "multi_observer.h"
338 #include "multi_endgame.h"
340 #include "neblightning.h"
341 #include "supernova.h"
342 #include "missionmessage.h"
343 #include "mainhallmenu.h"
345 #include "localize.h"
347 // --------------------------------------------------------------
349 // --------------------------------------------------------------
351 // --------------------------------------------------------------
353 // --------------------------------------------------------------
354 typedef struct asteroid_field {
355 vector min_bound; // Minimum range of field.
356 vector max_bound; // Maximum range of field.
357 vector vel; // Average asteroid moves at this velocity.
358 float speed; // Average speed of field
359 int num_initial_asteroids; // Number of asteroids at creation.
362 #define CHEAT_BUFFER_LEN 20
363 #define CHEATSPOT (CHEAT_BUFFER_LEN - 1)
365 char CheatBuffer[CHEAT_BUFFER_LEN+1];
367 #if defined(FS2_DEMO)
368 const char *Cheat_code_demo = NOX("33BE^(8]C01(:=BHt");
369 #elif defined(MAKE_FS1)
370 const char *Cheat_code_gr = NOX("BNdEgDB\\s?0XD1?0)"); // de:www.volition-inc.com
371 const char *Cheat_code = NOX("E5B?(\"=H'5UTE$o%D"); // www.volition-inc.com
372 const char *Cheat_code_movies = NOX("iC:1C06,'00SoXyY6"); // freespacestandsalone
374 const char *Cheat_code = NOX("33BE^(8]C01(:=BHt"); // www.freespace2.com
375 const char *Cheat_code_fish = NOX("bDc9y+$;#AIDRoouM"); // vasudanswuvfishes
376 const char *Cheat_code_headz = NOX("!;:::@>F7L?@@2:@A"); // humanheadsinside.
377 const char *Cheat_code_tooled = NOX("sipp-^rM@L!U^usjX"); // tooledworkedowned
378 const char *Cheat_code_pirate = NOX("MAP4YP[4=-2uC(yJ^"); // arrrrwalktheplank
379 const char *Cheat_code_skip = NOX("7!ICkSI\"(8n3JesBP"); // skipmemymissionyo
381 // 666)6=N79+Z45=BE0e
382 int Tool_enabled = 0;
386 // list of the cheat codes
388 // "DavidPerry" NOX("0!XZQ*K.pu");
389 // NOX("&BvWJe=a?$VP*=@2W,2Y"); // Super-secret 20 character string!
390 //NOX("STs`nHqW\\lv#KD_aCSWN"); // solveditonceandforall (note double \\ as string contains \.
392 char *Cheat_code_in_game = NOX("///FES)P<A5=7CCB!n10"); // www.volition-inc.com
393 char *Cheat_code_movies = NOX("&BvWJe=a?$VP*=@2W,2Y"); // freespacestandsalone
394 char *Cheat_code_pirate = NOX("%,sPzoE>\\+_(Qs#+h-8o"); // arrwalktheplankmatey
399 int All_movies_enabled = 0;
401 //int Debug_allowed = 0;
405 extern int AI_watch_object;
406 extern int Countermeasures_enabled;
408 extern fix Game_time_compression;
410 extern float do_subobj_hit_stuff(object *ship_obj, object *other_obj, vector *hitpos, float damage);
412 extern void mission_goal_mark_all_true( int type );
414 int Normal_key_set[] = {
417 TARGET_NEXT_CLOSEST_HOSTILE,
418 TARGET_PREV_CLOSEST_HOSTILE,
419 TARGET_NEXT_CLOSEST_FRIENDLY,
420 TARGET_PREV_CLOSEST_FRIENDLY,
421 TARGET_TARGETS_TARGET,
422 TARGET_SHIP_IN_RETICLE,
424 TARGET_LAST_TRANMISSION_SENDER,
426 TARGET_CLOSEST_SHIP_ATTACKING_TARGET,
427 TARGET_CLOSEST_SHIP_ATTACKING_SELF,
429 TOGGLE_AUTO_TARGETING,
430 TARGET_SUBOBJECT_IN_RETICLE,
431 TARGET_PREV_SUBOBJECT,
432 TARGET_NEXT_SUBOBJECT,
433 STOP_TARGETING_SUBSYSTEM,
435 TARGET_NEXT_UNINSPECTED_CARGO,
436 TARGET_PREV_UNINSPECTED_CARGO,
438 TARGET_NEXT_LIVE_TURRET,
439 TARGET_PREV_LIVE_TURRET,
446 ATTACK_SUBSYSTEM_MESSAGE,
465 TARGET_NEXT_ESCORT_SHIP,
491 TOGGLE_AUTO_MATCH_TARGET_SPEED,
494 VIEW_EXTERNAL_TOGGLE_CAMERA_LOCK,
495 LAUNCH_COUNTERMEASURE,
498 PLUS_5_PERCENT_THROTTLE,
499 MINUS_5_PERCENT_THROTTLE,
503 TARGET_CLOSEST_REPAIR_SHIP,
506 MULTI_MESSAGE_FRIENDLY,
507 MULTI_MESSAGE_HOSTILE,
508 MULTI_MESSAGE_TARGET,
509 MULTI_OBSERVER_ZOOM_TO,
517 MULTI_TOGGLE_NETINFO,
523 int Dead_key_set[] = {
526 TARGET_NEXT_CLOSEST_HOSTILE,
527 TARGET_PREV_CLOSEST_HOSTILE,
528 TARGET_NEXT_CLOSEST_FRIENDLY,
529 TARGET_PREV_CLOSEST_FRIENDLY,
530 TARGET_TARGETS_TARGET,
531 TARGET_CLOSEST_SHIP_ATTACKING_TARGET,
533 TOGGLE_AUTO_TARGETING,
534 TARGET_SUBOBJECT_IN_RETICLE,
535 TARGET_PREV_SUBOBJECT,
536 TARGET_NEXT_SUBOBJECT,
537 STOP_TARGETING_SUBSYSTEM,
539 TARGET_NEXT_LIVE_TURRET,
540 TARGET_PREV_LIVE_TURRET,
551 TARGET_NEXT_ESCORT_SHIP,
552 TARGET_CLOSEST_REPAIR_SHIP,
555 MULTI_MESSAGE_FRIENDLY,
556 MULTI_MESSAGE_HOSTILE,
557 MULTI_MESSAGE_TARGET,
558 MULTI_OBSERVER_ZOOM_TO,
564 int Critical_key_set[] = {
585 int Non_critical_key_set[] = {
589 TOGGLE_AUTO_MATCH_TARGET_SPEED,
592 TARGET_NEXT_CLOSEST_HOSTILE,
593 TARGET_PREV_CLOSEST_HOSTILE,
594 TOGGLE_AUTO_TARGETING,
595 TARGET_NEXT_CLOSEST_FRIENDLY,
596 TARGET_PREV_CLOSEST_FRIENDLY,
597 TARGET_SHIP_IN_RETICLE,
599 TARGET_LAST_TRANMISSION_SENDER,
601 TARGET_CLOSEST_REPAIR_SHIP,
602 TARGET_CLOSEST_SHIP_ATTACKING_TARGET,
604 TARGET_CLOSEST_SHIP_ATTACKING_SELF,
605 TARGET_TARGETS_TARGET,
606 TARGET_SUBOBJECT_IN_RETICLE,
607 TARGET_PREV_SUBOBJECT,
608 TARGET_NEXT_SUBOBJECT,
609 STOP_TARGETING_SUBSYSTEM,
612 TARGET_NEXT_UNINSPECTED_CARGO,
613 TARGET_PREV_UNINSPECTED_CARGO,
615 TARGET_NEXT_LIVE_TURRET,
616 TARGET_PREV_LIVE_TURRET,
620 ATTACK_SUBSYSTEM_MESSAGE,
631 VIEW_EXTERNAL_TOGGLE_CAMERA_LOCK,
639 TARGET_NEXT_ESCORT_SHIP,
641 MULTI_MESSAGE_FRIENDLY,
642 MULTI_MESSAGE_HOSTILE,
643 MULTI_MESSAGE_TARGET,
644 MULTI_OBSERVER_ZOOM_TO,
649 MULTI_TOGGLE_NETINFO,
656 // set sizes of the key sets automatically
657 int Normal_key_set_size = sizeof(Normal_key_set) / sizeof(int);
658 int Dead_key_set_size = sizeof(Dead_key_set) / sizeof(int);
659 int Critical_key_set_size = sizeof(Critical_key_set) / sizeof(int);
660 int Non_critical_key_set_size = sizeof(Non_critical_key_set) / sizeof(int);
662 // --------------------------------------------------------------
663 // routine to process keys used only for debugging
664 // --------------------------------------------------------------
667 void debug_cycle_player_ship(int delta)
669 if ( Player_obj == NULL )
672 int si_index = Ships[Player_obj->instance].ship_info_index;
677 if ( si_index > MAX_SHIP_TYPES ){
681 si_index = MAX_SHIP_TYPES - 1;
683 sip = &Ship_info[si_index];
684 if ( sip->flags & SIF_PLAYER_SHIP ){
690 if ( sanity > MAX_SHIP_TYPES ){
695 change_ship_type(Player_obj->instance, si_index);
696 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Player ship changed to %s", 0), Ship_info[si_index].name);
699 // cycle targeted ship to next ship in that species
700 void debug_cycle_targeted_ship(int delta)
704 int si_index, species;
705 char name[NAME_LENGTH];
707 if ( Player_ai->target_objnum == -1 )
710 objp = &Objects[Player_ai->target_objnum];
711 if ( objp->type != OBJ_SHIP )
714 si_index = Ships[objp->instance].ship_info_index;
715 SDL_assert(si_index != -1 );
716 species = Ship_info[si_index].species;
722 if ( si_index > MAX_SHIP_TYPES )
725 si_index = MAX_SHIP_TYPES-1;
728 sip = &Ship_info[si_index];
730 // if it has test in the name, jump over it
731 SDL_strlcpy(name, sip->name, SDL_arraysize(name));
733 if ( strstr(name,NOX("test")) != NULL )
736 if ( sip->species == species && (sip->flags & (SIF_FIGHTER | SIF_BOMBER | SIF_TRANSPORT) ) )
741 if ( sanity > MAX_SHIP_TYPES )
745 change_ship_type(objp->instance, si_index);
746 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Changed player target to %s", 1), Ship_info[si_index].name);
749 void debug_max_secondary_weapons(object *objp)
752 ship *shipp = &Ships[objp->instance];
753 ship_info *sip = &Ship_info[shipp->ship_info_index];
755 for ( index = 0; index < MAX_SECONDARY_BANKS; index++ ) {
756 shipp->weapons.secondary_bank_ammo[index] = sip->secondary_bank_ammo_capacity[index];
760 void debug_change_song(int delta)
763 if ( event_music_next_soundtrack(delta) != -1 ) {
764 event_music_get_soundtrack_name(buf, sizeof(buf));
765 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Soundtrack changed to: %s", 2), buf);
768 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Event music is not playing", 3));
772 //extern void set_global_ignore_object(int objnum);
774 extern void hud_target_asteroid();
775 extern int Framerate_delay;
777 extern void snd_stop_any_sound();
779 void process_debug_keys(int k)
782 if ( !Debug_allowed )
786 // if ( (k & KEY_DEBUGGED) && (Game_mode & GM_RECORDING_DEMO) )
790 case KEY_DEBUGGED + SDLK_h:
791 hud_target_toggle_hidden_from_sensors();
794 case KEY_DEBUGGED + SDLK_f:
797 for (i=0; i<NUM_HUD_GAUGES; i++) {
798 hud_gauge_start_flash(i);
801 extern int wacky_scheme;
802 if(wacky_scheme == 3){
809 case KEY_DEBUGGED + KEY_ALTED + SDLK_f:
810 Framerate_delay += 10;
811 HUD_printf(XSTR( "Framerate delay increased to %i milliseconds per frame.", 4), Framerate_delay);
814 case KEY_DEBUGGED + KEY_ALTED + KEY_SHIFTED + SDLK_f:
815 Framerate_delay -= 10;
816 if (Framerate_delay < 0)
819 HUD_printf(XSTR( "Framerate delay decreased to %i milliseconds per frame.", 5), Framerate_delay);
822 case KEY_DEBUGGED + SDLK_c:
823 case KEY_DEBUGGED1 + SDLK_c:
824 // hud_enemymsg_toggle();
825 if(Player_obj->flags & OF_COLLIDES){
826 obj_set_flags(Player_obj, Player_obj->flags & ~(OF_COLLIDES));
827 HUD_sourced_printf(HUD_SOURCE_HIDDEN, "Player no longer collides");
829 obj_set_flags(Player_obj, Player_obj->flags | OF_COLLIDES);
830 HUD_sourced_printf(HUD_SOURCE_HIDDEN, "Player collides");
834 case KEY_DEBUGGED + KEY_SHIFTED + SDLK_c:
835 case KEY_DEBUGGED1 + KEY_SHIFTED + SDLK_c:
836 Countermeasures_enabled = !Countermeasures_enabled;
837 HUD_printf(XSTR( "Countermeasure firing: %s", 6), Countermeasures_enabled ? XSTR( "ENABLED", 7) : XSTR( "DISABLED", 8));
840 case KEY_DEBUGGED + SDLK_e:
841 gameseq_post_event(GS_EVENT_EVENT_DEBUG);
844 case KEY_DEBUGGED + SDLK_COMMA:
845 if ( Game_time_compression > (F1_0/4) ){ // can't compress below 0.25
846 Game_time_compression /= 2;
849 case KEY_DEBUGGED + SDLK_PERIOD:
850 if ( Game_time_compression < (F1_0*8) ){
851 Game_time_compression *= 2;
855 // Kill! the currently targeted ship.
856 case KEY_DEBUGGED + SDLK_k:
857 case KEY_DEBUGGED1 + SDLK_k:
858 if (Player_ai->target_objnum != -1) {
859 object *objp = &Objects[Player_ai->target_objnum];
861 switch (objp->type) {
863 ship_apply_local_damage( objp, Player_obj, &objp->pos, 100000.0f, MISS_SHIELDS, CREATE_SPARKS);
864 ship_apply_local_damage( objp, Player_obj, &objp->pos, 1.0f, MISS_SHIELDS, CREATE_SPARKS);
867 Weapons[objp->instance].lifeleft = 0.01f;
874 // play the next mission message
875 case KEY_DEBUGGED + SDLK_v:
876 extern int Message_debug_index;
877 extern int Num_messages_playing;
878 // stop any other messages
879 if(Num_messages_playing){
884 if(Message_debug_index >= Num_messages - 1){
885 Message_debug_index = Num_builtin_messages;
887 Message_debug_index++;
891 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 );
892 if (Messages[Message_debug_index].avi_info.index == -1) {
893 HUD_printf("No anim set for message \"%s\"; None will play!", Messages[Message_debug_index].name);
897 // play the previous mission message
898 case KEY_DEBUGGED + KEY_SHIFTED + SDLK_v:
899 extern int Message_debug_index;
900 extern int Num_messages_playing;
901 // stop any other messages
902 if(Num_messages_playing){
906 // go maybe go down one
907 if(Message_debug_index == Num_builtin_messages - 1){
908 Message_debug_index = Num_builtin_messages;
909 } else if(Message_debug_index > Num_builtin_messages){
910 Message_debug_index--;
914 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 );
915 if (Messages[Message_debug_index].avi_info.index == -1) {
916 HUD_printf("No avi associated with this message; None will play!");
920 // reset to the beginning of mission messages
921 case KEY_DEBUGGED + KEY_ALTED + SDLK_v:
922 extern int Message_debug_index;
923 Message_debug_index = Num_builtin_messages - 1;
924 HUD_printf("Resetting to first mission message");
927 // Kill! the currently targeted ship.
928 case KEY_DEBUGGED + KEY_ALTED + KEY_SHIFTED + SDLK_k:
929 case KEY_DEBUGGED1 + KEY_ALTED + KEY_SHIFTED + SDLK_k:
930 if (Player_ai->target_objnum != -1) {
931 object *objp = &Objects[Player_ai->target_objnum];
933 if (objp->type == OBJ_SHIP) {
934 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);
939 // Kill the currently targeted subsystem.
940 case KEY_DEBUGGED + KEY_SHIFTED + SDLK_k:
941 case KEY_DEBUGGED1 + KEY_SHIFTED + SDLK_k:
942 if ((Player_ai->target_objnum != -1) && (Player_ai->targeted_subsys != NULL)) {
943 object *objp = &Objects[Player_ai->target_objnum];
944 if ( objp->type == OBJ_SHIP ) {
945 ship *sp = &Ships[objp->instance];
948 get_subsystem_world_pos(objp, Player_ai->targeted_subsys, &g_subobj_pos);
950 do_subobj_hit_stuff(objp, Player_obj, &g_subobj_pos, (float) -Player_ai->targeted_subsys->system_info->type); //100.0f);
952 if ( sp->subsys_info[SUBSYSTEM_ENGINE].current_hits <= 0.0f ) {
953 mission_log_add_entry(LOG_SHIP_DISABLED, sp->ship_name, NULL );
954 sp->flags |= SF_DISABLED; // add the disabled flag
957 if ( sp->subsys_info[SUBSYSTEM_TURRET].current_hits <= 0.0f ) {
958 mission_log_add_entry(LOG_SHIP_DISARMED, sp->ship_name, NULL );
959 // sp->flags |= SF_DISARMED; // add the disarmed flag
965 case KEY_DEBUGGED + KEY_ALTED + SDLK_k:
966 case KEY_DEBUGGED1 + KEY_ALTED + SDLK_k:
968 float shield, integrity;
971 vm_vec_rand_vec_quick(&randvec);
972 vm_vec_scale_add(&pos, &Player_obj->pos, &randvec, Player_obj->radius);
973 ship_apply_local_damage(Player_obj, Player_obj, &pos, 25.0f, MISS_SHIELDS, CREATE_SPARKS);
974 hud_get_target_strength(Player_obj, &shield, &integrity);
975 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "You knocked yourself down to %7.3f percent hull.\n", 9), 100.0f * integrity);
979 // Whack down the player's shield and hull by a little more than 50%
980 // Select next object to be viewed by AI.
981 case KEY_DEBUGGED + SDLK_i:
982 case KEY_DEBUGGED1 + SDLK_i:
983 Player_obj->flags ^= OF_INVULNERABLE;
984 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));
987 case KEY_DEBUGGED + KEY_SHIFTED + SDLK_i:
988 case KEY_DEBUGGED1 + KEY_SHIFTED + SDLK_i:
989 if (Player_ai->target_objnum != -1) {
990 object *objp = &Objects[Player_ai->target_objnum];
992 objp->flags ^= OF_INVULNERABLE;
993 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));
997 case KEY_DEBUGGED + KEY_ALTED + SDLK_i:
998 if (Player_ai->target_objnum != -1)
999 set_global_ignore_object(Player_ai->target_objnum);
1003 case KEY_DEBUGGED + SDLK_n:
1005 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Spewing debug info about object #%d", 14), AI_watch_object);
1008 case KEY_DEBUGGED + SDLK_o:
1010 case KEY_DEBUGGED1 + SDLK_o:
1012 toggle_player_object();
1015 case KEY_DEBUGGED + KEY_SHIFTED + SDLK_o:
1016 extern int Debug_octant;
1017 if(Debug_octant == 7){
1022 nprintf(("General", "Debug_octant == %d\n", Debug_octant));
1026 case KEY_DEBUGGED + SDLK_p:
1027 supernova_start(20);
1031 case KEY_DEBUGGED + SDLK_w:
1032 case KEY_DEBUGGED1 + SDLK_w:
1033 case KEY_DEBUGGED + KEY_SHIFTED + SDLK_w:
1034 case KEY_DEBUGGED1 + KEY_SHIFTED + SDLK_w:
1035 // temp code for testing purposes, toggles weapon energy cheat
1036 Weapon_energy_cheat = !Weapon_energy_cheat;
1037 if (Weapon_energy_cheat) {
1038 if (k & KEY_SHIFTED)
1039 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Weapon energy and missile count will always be at full ALL SHIPS!", 15));
1041 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Weapon energy and missile count will always be at full for player", 16));
1043 debug_max_secondary_weapons(Player_obj);
1044 if (k & KEY_SHIFTED) {
1047 for ( objp = GET_FIRST(&obj_used_list); objp !=END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp) )
1048 if (objp->type == OBJ_SHIP)
1049 debug_max_secondary_weapons(objp);
1053 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Normal weapon energy system / missile count restored", 17));
1057 case KEY_DEBUGGED + SDLK_g:
1059 case KEY_DEBUGGED1 + SDLK_g:
1061 mission_goal_mark_all_true( PRIMARY_GOAL );
1064 case KEY_DEBUGGED + SDLK_g + KEY_SHIFTED:
1066 case KEY_DEBUGGED1 + SDLK_g + KEY_SHIFTED:
1068 mission_goal_mark_all_true( SECONDARY_GOAL );
1071 case KEY_DEBUGGED + SDLK_g + KEY_ALTED:
1073 case KEY_DEBUGGED1 + SDLK_g + KEY_ALTED:
1075 mission_goal_mark_all_true( BONUS_GOAL );
1078 case KEY_DEBUGGED + SDLK_9: {
1079 case KEY_DEBUGGED1 + SDLK_9:
1082 shipp = &Ships[Player_obj->instance];
1083 shipp->weapons.secondary_bank_weapons[shipp->weapons.current_secondary_bank]++;
1084 if ( shipp->weapons.secondary_bank_weapons[shipp->weapons.current_secondary_bank] >= Num_weapon_types )
1085 shipp->weapons.secondary_bank_weapons[shipp->weapons.current_secondary_bank] = First_secondary_index;
1087 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);
1092 case KEY_DEBUGGED + KEY_SHIFTED + SDLK_9: {
1093 case KEY_DEBUGGED1 + KEY_SHIFTED + SDLK_9:
1096 shipp = &Ships[Player_obj->instance];
1097 shipp->weapons.secondary_bank_weapons[shipp->weapons.current_secondary_bank]--;
1098 if ( shipp->weapons.secondary_bank_weapons[shipp->weapons.current_secondary_bank] < 0)
1099 shipp->weapons.secondary_bank_weapons[shipp->weapons.current_secondary_bank] = Num_weapon_types - 1;
1101 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);
1106 #if !(defined(FS2_DEMO) || defined(FS1_DEMO))
1107 case KEY_DEBUGGED + SDLK_u: {
1108 case KEY_DEBUGGED1 + SDLK_u:
1110 extern asteroid_field Asteroid_field;
1111 object *asteroid_create(asteroid_field *asfieldp, int asteroid_type, int subtype);
1112 object *objp = asteroid_create(&Asteroid_field, 0, 0);
1114 vm_vec_copy_scale(&vel, &Player_obj->orient.v.fvec, 50.0f);
1115 objp->phys_info.vel = vel;
1116 objp->phys_info.desired_vel = vel;
1117 objp->pos = Player_obj->pos;
1118 //mission_goal_mark_all_true( PRIMARY_GOAL );
1123 case KEY_DEBUGGED + SDLK_0: {
1124 case KEY_DEBUGGED1 + SDLK_0:
1127 shipp = &Ships[Player_obj->instance];
1128 shipp->weapons.primary_bank_weapons[shipp->weapons.current_primary_bank]++;
1129 if ( shipp->weapons.primary_bank_weapons[shipp->weapons.current_primary_bank] >= First_secondary_index )
1130 shipp->weapons.primary_bank_weapons[shipp->weapons.current_primary_bank] = 0;
1132 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);
1136 case KEY_DEBUGGED + KEY_SHIFTED + SDLK_0: {
1137 case KEY_DEBUGGED1 + KEY_SHIFTED + SDLK_0:
1140 shipp = &Ships[Player_obj->instance];
1141 shipp->weapons.primary_bank_weapons[shipp->weapons.current_primary_bank]--;
1142 if ( shipp->weapons.primary_bank_weapons[shipp->weapons.current_primary_bank] < 0)
1143 shipp->weapons.primary_bank_weapons[shipp->weapons.current_primary_bank] = First_secondary_index-1 ;
1145 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);
1149 case KEY_DEBUGGED + SDLK_j: {
1150 int new_pattern = event_music_return_current_pattern();
1153 if ( new_pattern >= MAX_PATTERNS )
1156 event_music_change_pattern(new_pattern);
1160 case KEY_DEBUGGED + SDLK_m: {
1161 if ( Event_music_enabled ) {
1162 event_music_disable();
1163 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Event music disabled", 20));
1166 event_music_enable();
1167 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Event music enabled", 21));
1173 case KEY_DEBUGGED + SDLK_r: {
1174 // case KEY_DEBUGGED1 + SDLK_r:
1175 if (Player_ai->target_objnum != -1)
1176 ai_issue_rearm_request(&Objects[Player_ai->target_objnum]);
1178 ai_issue_rearm_request(Player_obj);
1183 case KEY_DEBUGGED + KEY_SHIFTED + SDLK_UP:
1184 Game_detail_level++;
1185 HUD_printf( XSTR( "Detail level set to %+d\n", 22), Game_detail_level );
1188 case KEY_DEBUGGED + KEY_SHIFTED + SDLK_DOWN:
1189 Game_detail_level--;
1190 HUD_printf( XSTR( "Detail level set to %+d\n", 22), Game_detail_level );
1194 case KEY_DEBUGGED + KEY_SHIFTED + SDLK_t: {
1195 extern int Test_begin;
1197 if ( Test_begin == 1 )
1201 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Frame Rate test started", 23));
1206 case KEY_DEBUGGED + SDLK_d:
1207 extern int OO_update_index;
1209 if(MULTIPLAYER_MASTER){
1212 } while((OO_update_index < (MAX_PLAYERS-1)) && !MULTI_CONNECTED(Net_players[OO_update_index]));
1213 if(OO_update_index >= MAX_PLAYERS-1){
1214 OO_update_index = -1;
1217 if(OO_update_index < 0){
1218 OO_update_index = MY_NET_PLAYER_NUM;
1220 OO_update_index = -1;
1225 // change player ship to next flyable type
1226 case KEY_DEBUGGED + SDLK_RIGHT:
1227 debug_cycle_player_ship(1);
1230 // change player ship to previous flyable ship
1231 case KEY_DEBUGGED + SDLK_LEFT:
1232 debug_cycle_player_ship(-1);
1235 // cycle target to ship
1236 case KEY_DEBUGGED + KEY_SHIFTED + SDLK_RIGHT:
1237 debug_cycle_targeted_ship(1);
1240 // cycle target to previous ship
1241 case KEY_DEBUGGED + KEY_SHIFTED + SDLK_LEFT:
1242 debug_cycle_targeted_ship(-1);
1245 // change species of the targeted ship
1246 case KEY_DEBUGGED + SDLK_s: {
1247 if ( Player_ai->target_objnum < 0 )
1253 objp = &Objects[Player_ai->target_objnum];
1254 if ( objp->type != OBJ_SHIP )
1257 sip = &Ship_info[Ships[objp->instance].ship_info_index];
1259 if ( sip->species > SPECIES_SHIVAN )
1262 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Species of target changed to: %s", 24), Species_names[sip->species]);
1266 case KEY_DEBUGGED + KEY_SHIFTED + SDLK_s:
1267 game_increase_skill_level();
1268 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Skill level set to %s.", 25), Skill_level_names(Game_skill_level));
1272 // kill all missiles
1273 case KEY_DEBUGGED + KEY_SHIFTED + SDLK_1:
1276 case KEY_DEBUGGED + KEY_SHIFTED + SDLK_2:
1279 case KEY_DEBUGGED + KEY_SHIFTED + SDLK_3:
1282 case KEY_DEBUGGED + KEY_SHIFTED + SDLK_4:
1285 case KEY_DEBUGGED + KEY_SHIFTED + SDLK_5:
1288 case KEY_DEBUGGED + KEY_SHIFTED + SDLK_6:
1291 case KEY_DEBUGGED + KEY_SHIFTED + SDLK_7:
1294 case KEY_DEBUGGED + KEY_SHIFTED + SDLK_8:
1297 case KEY_DEBUGGED + KEY_SHIFTED + SDLK_9:
1301 case KEY_DEBUGGED + KEY_CTRLED + SDLK_1:
1304 case KEY_DEBUGGED + KEY_CTRLED + SDLK_2:
1307 case KEY_DEBUGGED + KEY_CTRLED + SDLK_3:
1312 case KEY_DEBUGGED + SDLK_t: {
1314 event_music_get_info(buf, sizeof(buf));
1315 HUD_sourced_printf(HUD_SOURCE_HIDDEN, buf);
1319 case KEY_DEBUGGED + SDLK_UP:
1320 debug_change_song(1);
1323 case KEY_DEBUGGED + SDLK_DOWN:
1324 debug_change_song(-1);
1328 case SDLK_KP_MINUS: {
1331 if ( key_pressed(SDLK_1) ) {
1336 if ( key_pressed(SDLK_2) ) {
1338 HUD_color_green -= 4;
1341 if ( key_pressed(SDLK_3) ) {
1343 HUD_color_blue -= 4;
1353 case KEY_DEBUGGED + SDLK_y:
1355 // blast a debug lightning bolt in front of the player
1356 vector start, strike;
1358 vm_vec_scale_add(&start, &Player_obj->pos, &Player_obj->orient.fvec, 300.0f);
1359 vm_vec_scale_add2(&start, &Player_obj->orient.rvec, -300.0f);
1360 vm_vec_scale_add(&strike, &start, &Player_obj->orient.rvec, 600.0f);
1361 nebl_bolt(DEBUG_BOLT, &start, &strike);
1368 case SDLK_KP_PLUS: {
1371 if ( key_pressed(SDLK_1) ) {
1376 if ( key_pressed(SDLK_2) ) {
1378 HUD_color_green += 4;
1381 if ( key_pressed(SDLK_3) ) {
1383 HUD_color_blue += 4;
1397 void ppsk_hotkeys(int k)
1400 #if !(defined(FS2_DEMO) || defined(FS1_DEMO))
1402 // use k to check for keys that can have Shift,Ctrl,Alt,Del status
1406 k &= ~KEY_DEBUGGED; // since hitting F11 will set this bit
1418 hotkey_set = mission_hotkey_get_set_num(k);
1419 if ( !(Players[Player_num].flags & PLAYER_FLAGS_MSG_MODE) )
1420 hud_target_hotkey_select( hotkey_set );
1422 hud_squadmsg_hotkey_select( hotkey_set );
1426 case SDLK_F5 + KEY_SHIFTED:
1427 case SDLK_F6 + KEY_SHIFTED:
1428 case SDLK_F7 + KEY_SHIFTED:
1429 case SDLK_F8 + KEY_SHIFTED:
1430 case SDLK_F9 + KEY_SHIFTED:
1431 case SDLK_F10 + KEY_SHIFTED:
1432 case SDLK_F11 + KEY_SHIFTED:
1433 case SDLK_F12 + KEY_SHIFTED:
1434 hotkey_set = mission_hotkey_get_set_num(k&(~KEY_SHIFTED));
1435 mprintf(("Adding to set %d\n", hotkey_set+1));
1436 if ( Player_ai->target_objnum == -1)
1437 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "No target to add/remove from set %d.", 26), hotkey_set+1);
1439 hud_target_hotkey_add_remove( hotkey_set, &Objects[Player_ai->target_objnum], HOTKEY_USER_ADDED);
1440 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);
1445 case SDLK_F5 + KEY_SHIFTED + KEY_ALTED:
1446 case SDLK_F6 + KEY_SHIFTED + KEY_ALTED:
1447 case SDLK_F7 + KEY_SHIFTED + KEY_ALTED:
1448 case SDLK_F8 + KEY_SHIFTED + KEY_ALTED:
1449 case SDLK_F9 + KEY_SHIFTED + KEY_ALTED:
1450 case SDLK_F10 + KEY_SHIFTED + KEY_ALTED:
1451 case SDLK_F11 + KEY_SHIFTED + KEY_ALTED:
1452 case SDLK_F12 + KEY_SHIFTED + KEY_ALTED:
1453 hotkey_set = mission_hotkey_get_set_num(k & ~(KEY_SHIFTED+KEY_ALTED));
1454 hud_target_hotkey_clear( hotkey_set );
1457 case KEY_SHIFTED + SDLK_MINUS:
1458 if ( HUD_color_alpha > HUD_COLOR_ALPHA_USER_MIN ) {
1463 /* case KEY_SHIFTED + SDLK_u:
1465 object *debris_create(object *source_obj, int model_num, int submodel_num, vector *pos, vector *exp_center, int hull_flag, float exp_force);
1467 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);
1469 temp->hull_strength = 5000.0f;
1470 int objnum = temp - Objects;
1471 vm_vec_copy_scale(&Objects[objnum].phys_info.vel, &Player_obj->orient.fvec, 30.0f);
1477 case KEY_SHIFTED + SDLK_EQUALS:
1478 if ( HUD_color_alpha < HUD_COLOR_ALPHA_USER_MAX ) {
1489 // check keypress 'key' against a set of valid controls and mark the match in the
1490 // player's button info bitfield. Also checks joystick controls in the set.
1492 // key = scancode (plus modifiers).
1493 // count = total size of the list
1494 // list = list of Control_config struct action indices to check for
1495 void process_set_of_keys(int key, int count, int *list)
1499 for (i=0; i<count; i++)
1500 if (check_control(list[i], key))
1501 button_info_set(&Player->bi, list[i]);
1504 // routine to process keys used for player ship stuff (*not* ship movement).
1505 void process_player_ship_keys(int k)
1509 masked_k = k & ~KEY_CTRLED; // take out CTRL modifier only
1511 // moved this line to beginning of function since hotkeys now encompass
1512 // F5 - F12. We can return after using F11 as a hotkey.
1513 ppsk_hotkeys(masked_k);
1514 if (key_pressed(KEY_DEBUG_KEY)){
1518 // if we're in supernova mode. do nothing
1519 if(Player->control_mode == PCM_SUPERNOVA){
1523 // pass the key to the squadmate messaging code. If the messaging code took the key, then return
1524 // from here immediately since we don't want to do further key processing.
1525 if ( hud_squadmsg_read_key(k) )
1528 if ( Player->control_mode == PCM_NORMAL ) {
1529 // The following things are not legal to do while dead.
1530 if ( !(Game_mode & GM_DEAD) ) {
1531 process_set_of_keys(masked_k, Normal_key_set_size, Normal_key_set);
1533 process_set_of_keys(masked_k, Dead_key_set_size, Dead_key_set);
1540 // Handler for when player hits 'ESC' during the game
1541 void game_do_end_mission_popup()
1543 int pf_flags, choice;
1544 // char savegame_filename[_MAX_FNAME];
1546 // do the multiplayer version of this
1547 if(Game_mode & GM_MULTIPLAYER){
1548 multi_quit_game(PROMPT_ALL);
1551 // single player version....
1552 // do housekeeping things.
1554 game_stop_looped_sounds();
1557 pf_flags = PF_BODY_BIG | PF_USE_AFFIRMATIVE_ICON | PF_USE_NEGATIVE_ICON;
1558 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));
1562 // save the game before quitting if in campaign mode
1563 // MWA -- 3/26/98 -- no more save/restore!!!!
1565 if ( Game_mode & GM_CAMPAIGN_MODE ) {
1566 memset(savegame_filename, 0, _MAX_FNAME);
1567 mission_campaign_savefile_generate_root(savegame_filename);
1568 strcat(savegame_filename, NOX("svg"));
1569 if ( state_save_all(savegame_filename) ) {
1570 Int3(); // could not save this game
1574 gameseq_post_event(GS_EVENT_END_GAME);
1578 gameseq_post_event(GS_EVENT_ENTER_GAME);
1582 break; // do nothing
1590 // handle pause keypress
1591 void game_process_pause_key()
1593 // special processing for multiplayer
1594 if (Game_mode & GM_MULTIPLAYER) {
1595 if(Multi_pause_status){
1596 multi_pause_request(0);
1598 multi_pause_request(1);
1601 gameseq_post_event( GS_EVENT_PAUSE_GAME );
1605 #define WITHIN_BBOX() do { \
1606 float scale = 2.0f; \
1607 polymodel *pm = model_get(s_check->modelnum); \
1610 vector temp = new_obj->pos; \
1612 vm_vec_sub2(&temp, &hit_check->pos); \
1613 vm_vec_rotate(&gpos, &temp, &hit_check->orient); \
1614 if((gpos.xyz.x >= pm->mins.xyz.x * scale) && (gpos.xyz.y >= pm->mins.xyz.y * scale) && (gpos.xyz.z >= pm->mins.xyz.z * scale) && (gpos.xyz.x <= pm->maxs.xyz.x * scale) && (gpos.xyz.y <= pm->maxs.xyz.y * scale) && (gpos.xyz.z <= pm->maxs.xyz.z * scale)) { \
1620 #define MOVE_AWAY_BBOX() do { \
1621 polymodel *pm = model_get(s_check->modelnum); \
1623 switch((int)frand_range(0.0f, 3.9f)){ \
1625 new_obj->pos.xyz.x += 200.0f; \
1628 new_obj->pos.xyz.x -= 200.0f; \
1631 new_obj->pos.xyz.y += 200.0f; \
1634 new_obj->pos.xyz.y -= 200.0f; \
1637 new_obj->pos.xyz.z -= 200.0f; \
1643 // process cheat codes
1644 void game_process_cheats(int k)
1653 // no cheats in multiplayer, ever
1654 if(Game_mode & GM_MULTIPLAYER){
1659 k = key_get_text_input();
1661 if ( (k < 0) || (k > 255) ) {
1665 for (i = 0; i < CHEAT_BUFFER_LEN; i++){
1666 CheatBuffer[i]=CheatBuffer[i+1];
1669 CheatBuffer[CHEATSPOT]=(char)k;
1671 cryptstring=jcrypt(&CheatBuffer[CHEAT_BUFFER_LEN - CRYPT_STRING_LENGTH]);
1673 #if defined(FS2_DEMO)
1674 if ( !strcmp(Cheat_code_demo, cryptstring) ) {
1675 HUD_printf(XSTR( "Cheats enabled.", 31));
1677 if (Player->flags & PLAYER_FLAGS_MSG_MODE){
1678 hud_squadmsg_toggle();
1685 // two possible cheat codes for FS1, German and English
1687 if( !strcmp(Cheat_code_gr, cryptstring) && !(Game_mode & GM_MULTIPLAYER)){
1689 HUD_printf("Cheats enabled");
1692 if( !strcmp(Cheat_code, cryptstring) && !(Game_mode & GM_MULTIPLAYER)){
1694 HUD_printf("Cheats enabled");
1698 if( !strcmp(Cheat_code, cryptstring) && !(Game_mode & GM_MULTIPLAYER)){
1700 HUD_printf("Cheats enabled");
1705 if( !strcmp(Cheat_code_fish, cryptstring) ){
1706 // only enable in the main hall
1707 if((gameseq_get_state() == GS_STATE_MAIN_MENU) && (main_hall_id() == 1)){
1708 extern void fishtank_start();
1712 if( !strcmp(Cheat_code_headz, cryptstring) ){
1713 main_hall_vasudan_funny();
1715 if( !strcmp(Cheat_code_skip, cryptstring) && (gameseq_get_state() == GS_STATE_MAIN_MENU)){
1716 extern void main_hall_campaign_cheat();
1717 main_hall_campaign_cheat();
1719 if( !strcmp(Cheat_code_tooled, cryptstring) && (Game_mode & GM_IN_MISSION)){
1721 HUD_printf("Prepare to be taken to school");
1723 if( !strcmp(Cheat_code_pirate, cryptstring) && (Game_mode & GM_IN_MISSION) && (Player_obj != NULL)){
1724 HUD_printf(NOX("Walk the plank"));
1726 for(int idx=0; idx<1; idx++){
1727 vector add = Player_obj->pos;
1728 add.xyz.x += frand_range(-700.0f, 700.0f);
1729 add.xyz.y += frand_range(-700.0f, 700.0f);
1730 add.xyz.z += frand_range(-700.0f, 700.0f);
1732 int objnum = ship_create(&vmd_identity_matrix, &add, Num_ship_types - 1);
1739 object *new_obj = &Objects[objnum];
1742 // now make sure we're not colliding with anyone
1745 moveup = GET_FIRST(&Ship_obj_list);
1746 while(moveup!=END_OF_LIST(&Ship_obj_list)){
1747 // don't check the new_obj itself!!
1748 if(moveup->objnum != objnum){
1749 hit_check = &Objects[moveup->objnum];
1750 SDL_assert(hit_check->type == OBJ_SHIP);
1751 SDL_assert(hit_check->instance >= 0);
1752 if((hit_check->type != OBJ_SHIP) || (hit_check->instance < 0)){
1755 s_check = &Ships[hit_check->instance];
1757 // just to make sure we don't get any strange magnitude errors
1758 if(vm_vec_same(&hit_check->pos, &Objects[objnum].pos)){
1759 Objects[objnum].pos.xyz.x += 1.0f;
1769 moveup = GET_NEXT(moveup);
1774 shipfx_warpin_start(&Objects[objnum]);
1776 // tell him to attack
1777 // ai_add_ship_goal_player( AIG_TYPE_PLAYER_SHIP, AI_GOAL_CHASE_ANY, SM_ATTACK, NULL, &Ai_info[Ships[Objects[objnum].instance].ai_index] );
1784 #if defined(MAKE_FS1) && !defined(FS1_DEMO)
1785 if ( !strcmp(Cheat_code_movies, cryptstring) ) {
1786 HUD_printf(XSTR( "All movies available in Tech Room", 32));
1787 All_movies_enabled = 1;
1788 if (Player->flags & PLAYER_FLAGS_MSG_MODE){
1789 hud_squadmsg_toggle();
1795 //#ifdef INTERPLAYQA
1796 if ( !strcmp(Cheat_code_in_game, cryptstring) ) {
1797 HUD_printf(XSTR( "Cheats enabled.", 31));
1799 if (Player->flags & PLAYER_FLAGS_MSG_MODE){
1800 hud_squadmsg_toggle();
1802 } else if ( !strcmp(Cheat_code_movies, cryptstring) ) {
1803 HUD_printf(XSTR( "All movies available in Tech Room", 32));
1804 All_movies_enabled = 1;
1805 if (Player->flags & PLAYER_FLAGS_MSG_MODE){
1806 hud_squadmsg_toggle();
1808 } else if( !strcmp(Cheat_code_pirate, cryptstring) ){
1809 HUD_printf(NOX("Walk the plank"));
1811 for(int idx=0; idx<1; idx++){
1813 add.x = frand_range(-1000.0f, 1000.0f);
1814 add.y = frand_range(-1000.0f, 1000.0f);
1815 add.z = frand_range(-1000.0f, 1000.0f);
1817 int objnum = ship_create(&vmd_identity_matrix, &add, Num_ship_types - 1);
1820 shipfx_warpin_start(&Objects[objnum]);
1828 void game_process_keys()
1832 button_info_clear(&Player->bi); // clear out the button info struct for the player
1836 // AL 12-10-97: Scan for keys used to leave the dead state (don't process any)
1837 // DB 1-13-98 : New popup code will run the game do state, so we must skip
1838 // all key processing in this function, since everything should be run through the popup dialog
1839 if ( Game_mode & GM_DEAD_BLEW_UP ) {
1843 game_process_cheats( k );
1845 // mwa -- 4/5/97 Moved these two function calls before the switch statement. I don't think
1846 // that this has adverse affect on anything and is acutally desireable because of the
1847 // ESC key being used to quit any HUD message/input mode that might be currently in use
1848 process_player_ship_keys(k);
1851 process_debug_keys(k); // Note, also processed for cheats.
1860 if ( Player->control_mode != PCM_NORMAL ) {
1861 if ( Player->control_mode == PCM_WARPOUT_STAGE1 ) {
1862 gameseq_post_event( GS_EVENT_PLAYER_WARPOUT_STOP );
1864 // too late to abort warp out!
1867 // let the ESC key break out of messaging mode
1868 if ( Players[Player_num].flags & PLAYER_FLAGS_MSG_MODE ) {
1869 hud_squadmsg_toggle();
1873 // if in external view or chase view, go back to cockpit view
1874 if ( Viewer_mode & (VM_EXTERNAL|VM_CHASE|VM_OTHER_SHIP) ) {
1875 Viewer_mode &= ~(VM_EXTERNAL|VM_CHASE|VM_OTHER_SHIP);
1879 if (!(Game_mode & GM_DEAD_DIED))
1880 game_do_end_mission_popup();
1891 case KEY_ALTED + KEY_SHIFTED+SDLK_j:
1892 // treat the current joystick position as the center position
1896 case KEY_DEBUGGED | SDLK_PAUSE:
1897 gameseq_post_event( GS_EVENT_DEBUG_PAUSE_GAME );
1901 game_process_pause_key();
1906 button_info_do(&Player->bi); // call functions based on status of button_info bit vectors
1909 int button_function_critical(int n, net_player *p = NULL)
1914 int at_self; // flag indicating the object is local (for hud messages, etc)
1918 // multiplayer clients should leave critical button bits alone and pass them to the server instead
1919 if ((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER)) {
1920 // if this flag is set, we should apply the button itself (came from the server)
1921 if (!Multi_button_info_ok){
1926 // in single player mode make sure we're using the player object and the player himself, otherwise use the object and
1927 // player pertaining to the passed net_player
1932 if(Game_mode & GM_MULTIPLAYER){
1935 // if we're the server in multiplayer and we're an observer, don't process our own critical button functions
1936 if((Net_player->flags & NETINFO_FLAG_AM_MASTER) && (Net_player->flags & NETINFO_FLAG_OBSERVER)){
1942 objp = &Objects[p->player->objnum];
1947 if ( NETPLAYER_IS_DEAD(npl) || (Ships[Objects[pl->objnum].instance].flags & SF_DYING) )
1952 // cycle to next secondary weapon
1953 case CYCLE_SECONDARY:
1955 control_used(CYCLE_SECONDARY);
1957 hud_gauge_popup_start(HUD_WEAPONS_GAUGE);
1958 if (ship_select_next_secondary(objp)) {
1959 ship* shipp = &Ships[objp->instance];
1960 if ( timestamp_elapsed(shipp->weapons.next_secondary_fire_stamp[shipp->weapons.current_secondary_bank]) ) {
1961 shipp->weapons.next_secondary_fire_stamp[shipp->weapons.current_secondary_bank] = timestamp(250); // 1/4 second delay until can fire
1964 // multiplayer server should maintain bank/link status here
1965 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
1966 SDL_assert(npl != NULL);
1967 multi_server_update_player_weapons(npl,shipp);
1972 // cycle number of missiles
1973 case CYCLE_NUM_MISSLES:
1975 control_used(CYCLE_NUM_MISSLES);
1977 if ( objp == Player_obj ) {
1978 if ( Player_ship->weapons.num_secondary_banks <= 0 ) {
1979 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "This ship has no secondary weapons", 33));
1980 gamesnd_play_iface(SND_GENERAL_FAIL);
1985 if ( Ships[objp->instance].flags & SF_SECONDARY_DUAL_FIRE ) {
1986 Ships[objp->instance].flags &= ~SF_SECONDARY_DUAL_FIRE;
1988 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Secondary weapon set to normal fire mode", 34));
1989 snd_play( &Snds[SND_SECONDARY_CYCLE] );
1990 hud_gauge_popup_start(HUD_WEAPONS_GAUGE);
1993 Ships[objp->instance].flags |= SF_SECONDARY_DUAL_FIRE;
1995 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Secondary weapon set to dual fire mode", 35));
1996 snd_play( &Snds[SND_SECONDARY_CYCLE] );
1997 hud_gauge_popup_start(HUD_WEAPONS_GAUGE);
2001 // multiplayer server should maintain bank/link status here
2002 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
2003 SDL_assert(npl != NULL);
2004 multi_server_update_player_weapons(npl,&Ships[objp->instance]);
2008 // increase weapon recharge rate
2009 case INCREASE_WEAPON:
2011 control_used(INCREASE_WEAPON);
2012 increase_recharge_rate(objp, WEAPONS);
2014 // multiplayer server should maintain bank/link status here
2015 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
2016 SDL_assert(npl != NULL);
2017 multi_server_update_player_weapons(npl,&Ships[objp->instance]);
2021 // decrease weapon recharge rate
2022 case DECREASE_WEAPON:
2024 control_used(DECREASE_WEAPON);
2025 decrease_recharge_rate(objp, WEAPONS);
2027 // multiplayer server should maintain bank/link status here
2028 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
2029 SDL_assert(npl != NULL);
2030 multi_server_update_player_weapons(npl,&Ships[objp->instance]);
2034 // increase shield recharge rate
2035 case INCREASE_SHIELD:
2037 control_used(INCREASE_SHIELD);
2038 increase_recharge_rate(objp, SHIELDS);
2040 // multiplayer server should maintain bank/link status here
2041 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
2042 SDL_assert(npl != NULL);
2043 multi_server_update_player_weapons(npl,&Ships[objp->instance]);
2047 // decrease shield recharge rate
2048 case DECREASE_SHIELD:
2050 control_used(DECREASE_SHIELD);
2051 decrease_recharge_rate(objp, SHIELDS);
2053 // multiplayer server should maintain bank/link status here
2054 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
2055 SDL_assert(npl != NULL);
2056 multi_server_update_player_weapons(npl,&Ships[objp->instance]);
2060 // increase energy to engines
2061 case INCREASE_ENGINE:
2063 control_used(INCREASE_ENGINE);
2064 increase_recharge_rate(objp, ENGINES);
2066 // multiplayer server should maintain bank/link status here
2067 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
2068 SDL_assert(npl != NULL);
2069 multi_server_update_player_weapons(npl,&Ships[objp->instance]);
2073 // decrease energy to engines
2074 case DECREASE_ENGINE:
2076 control_used(DECREASE_ENGINE);
2077 decrease_recharge_rate(objp, ENGINES);
2079 // multiplayer server should maintain bank/link status here
2080 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
2081 SDL_assert(npl != NULL);
2082 multi_server_update_player_weapons(npl,&Ships[objp->instance]);
2087 // equalize recharge rates
2090 control_used(ETS_EQUALIZE);
2093 set_default_recharge_rates(objp);
2094 snd_play( &Snds[SND_ENERGY_TRANS] );
2095 // multiplayer server should maintain bank/link status here
2096 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
2097 SDL_assert(npl != NULL);
2098 multi_server_update_player_weapons(npl,&Ships[objp->instance]);
2103 // equalize shield energy to all quadrants
2104 case SHIELD_EQUALIZE:
2106 control_used(SHIELD_EQUALIZE);
2108 hud_shield_equalize(objp, pl);
2111 // transfer shield energy to front
2112 case SHIELD_XFER_TOP:
2114 control_used(SHIELD_XFER_TOP);
2116 hud_augment_shield_quadrant(objp, 1);
2119 // transfer shield energy to rear
2120 case SHIELD_XFER_BOTTOM:
2122 control_used(SHIELD_XFER_BOTTOM);
2123 hud_augment_shield_quadrant(objp, 2);
2126 // transfer shield energy to left
2127 case SHIELD_XFER_LEFT:
2129 control_used(SHIELD_XFER_LEFT);
2130 hud_augment_shield_quadrant(objp, 3);
2133 // transfer shield energy to right
2134 case SHIELD_XFER_RIGHT:
2136 control_used(SHIELD_XFER_RIGHT);
2137 hud_augment_shield_quadrant(objp, 0);
2140 // transfer energy to shield from weapons
2143 control_used(XFER_SHIELD);
2144 transfer_energy_to_shields(objp);
2147 // transfer energy to weapons from shield
2150 control_used(XFER_LASER);
2151 transfer_energy_to_weapons(objp);
2154 // following are not handled here, but we need to bypass the Int3()
2155 case LAUNCH_COUNTERMEASURE:
2158 case VIEW_EXTERNAL_TOGGLE_CAMERA_LOCK:
2159 case ONE_THIRD_THROTTLE:
2160 case TWO_THIRDS_THROTTLE:
2161 case MINUS_5_PERCENT_THROTTLE:
2162 case PLUS_5_PERCENT_THROTTLE:
2168 Int3(); // bad bad bad
2175 // return !0 if the action is allowed, otherwise return 0
2176 int button_allowed(int n)
2178 if ( hud_disabled() ) {
2182 case CYCLE_NEXT_PRIMARY:
2183 case CYCLE_PREV_PRIMARY:
2184 case CYCLE_SECONDARY:
2185 case ONE_THIRD_THROTTLE:
2186 case TWO_THIRDS_THROTTLE:
2187 case PLUS_5_PERCENT_THROTTLE:
2188 case MINUS_5_PERCENT_THROTTLE:
2200 // execute function corresponding to action n
2201 // basically, these are actions which don't affect demo playback at all
2202 int button_function_demo_valid(int n)
2204 // 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
2208 // No keys, not even targeting keys, when player in death roll. He can press keys after he blows up.
2209 if (Game_mode & GM_DEAD_DIED){
2213 // any of these buttons are valid
2216 control_used(VIEW_CHASE);
2217 Viewer_mode ^= VM_CHASE;
2218 if ( Viewer_mode & VM_CHASE ) {
2219 Viewer_mode &= ~VM_EXTERNAL;
2225 control_used(VIEW_EXTERNAL);
2226 Viewer_mode ^= VM_EXTERNAL;
2227 Viewer_mode &= ~VM_EXTERNAL_CAMERA_LOCKED; // reset camera lock when leave/entering external view
2228 if ( Viewer_mode & VM_EXTERNAL ) {
2229 Viewer_mode &= ~VM_CHASE;
2234 case VIEW_EXTERNAL_TOGGLE_CAMERA_LOCK:
2235 control_used(VIEW_EXTERNAL_TOGGLE_CAMERA_LOCK);
2236 if ( Viewer_mode & VM_EXTERNAL ) {
2237 Viewer_mode ^= VM_EXTERNAL_CAMERA_LOCKED;
2238 if ( Viewer_mode & VM_EXTERNAL_CAMERA_LOCKED ) {
2239 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "External camera is locked, controls will move ship", 36));
2241 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "External camera is free, controls will move the camera, not the ship", 37));
2247 case VIEW_OTHER_SHIP:
2248 control_used(VIEW_OTHER_SHIP);
2249 if ( Player_ai->target_objnum < 0 ) {
2250 snd_play( &Snds[SND_TARGET_FAIL] );
2252 if ( Objects[Player_ai->target_objnum].type != OBJ_SHIP ) {
2253 snd_play( &Snds[SND_TARGET_FAIL] );
2255 Viewer_mode ^= VM_OTHER_SHIP;
2261 case TIME_SLOW_DOWN:
2262 if ( Game_mode & GM_NORMAL ) {
2263 if ( Game_time_compression > F1_0) {
2264 Game_time_compression /= 2;
2266 gamesnd_play_error_beep();
2269 gamesnd_play_error_beep();
2275 if ( Game_mode & GM_NORMAL ) {
2276 if ( Game_time_compression < (F1_0*4) ) {
2277 Game_time_compression *= 2;
2279 gamesnd_play_error_beep();
2282 gamesnd_play_error_beep();
2292 // execute function corresponding to action n (BUTTON_ #define from KeyControl.h)
2293 int button_function(int n)
2297 if ( !button_allowed(n) ) {
2301 // No keys, not even targeting keys, when player in death roll. He can press keys after he blows up.
2302 if (Game_mode & GM_DEAD_DIED){
2307 // cycle to next primary weapon
2308 case CYCLE_NEXT_PRIMARY:
2310 if((Player_obj == NULL) || (Player_ship == NULL)){
2314 hud_gauge_popup_start(HUD_WEAPONS_GAUGE);
2315 if (ship_select_next_primary(Player_obj, CYCLE_PRIMARY_NEXT)) {
2316 ship* shipp = Player_ship;
2317 shipp->weapons.next_primary_fire_stamp[shipp->weapons.current_primary_bank] = timestamp(250); // 1/4 second delay until can fire
2318 // multiplayer server should maintain bank/link status here
2319 // if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
2320 // SDL_assert(npl != NULL);
2321 // multi_server_update_player_weapons(npl,shipp);
2326 // cycle to previous primary weapon
2327 case CYCLE_PREV_PRIMARY:
2329 if((Player_obj == NULL) || (Player_ship == NULL)){
2333 hud_gauge_popup_start(HUD_WEAPONS_GAUGE);
2334 if (ship_select_next_primary(Player_obj, CYCLE_PRIMARY_PREV)) {
2335 ship* shipp = Player_ship;
2336 shipp->weapons.next_primary_fire_stamp[shipp->weapons.current_primary_bank] = timestamp(250); // 1/4 second delay until can fire
2338 // multiplayer server should maintain bank/link status here
2339 // if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
2340 // SDL_assert(npl != NULL);
2341 // multi_server_update_player_weapons(npl,shipp);
2346 // cycle to next secondary weapon
2347 case CYCLE_SECONDARY:
2348 return button_function_critical(CYCLE_SECONDARY);
2351 // cycle number of missiles fired from secondary bank
2352 case CYCLE_NUM_MISSLES:
2353 return button_function_critical(CYCLE_NUM_MISSLES);
2356 // undefined in multiplayer for clients right now
2357 // match target speed
2358 case MATCH_TARGET_SPEED:
2359 control_used(MATCH_TARGET_SPEED);
2360 // If player is auto-matching, break auto-match speed
2361 if ( Player->flags & PLAYER_FLAGS_AUTO_MATCH_SPEED ) {
2362 Player->flags &= ~PLAYER_FLAGS_AUTO_MATCH_SPEED;
2364 player_match_target_speed();
2367 // undefined in multiplayer for clients right now
2368 // toggle auto-match target speed
2369 case TOGGLE_AUTO_MATCH_TARGET_SPEED:
2370 // multiplayer observers can't match target speed
2371 if((Game_mode & GM_MULTIPLAYER) && (Net_player != NULL) && ((Net_player->flags & NETINFO_FLAG_OBSERVER) || (Player_obj->type == OBJ_OBSERVER)) ){
2375 Player->flags ^= PLAYER_FLAGS_AUTO_MATCH_SPEED;
2376 control_used(TOGGLE_AUTO_MATCH_TARGET_SPEED);
2377 hud_gauge_popup_start(HUD_AUTO_SPEED);
2378 if ( Players[Player_num].flags & PLAYER_FLAGS_AUTO_MATCH_SPEED ) {
2379 snd_play(&Snds[SND_SHIELD_XFER_OK], 1.0f);
2380 // HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Auto match target speed activated", -1));
2381 if ( !(Player->flags & PLAYER_FLAGS_MATCH_TARGET) ) {
2382 player_match_target_speed();
2386 // HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Auto match target deactivated", -1));
2387 snd_play(&Snds[SND_SHIELD_XFER_OK], 1.0f);
2388 player_match_target_speed();
2394 control_used(TARGET_NEXT);
2395 if ( hud_sensors_ok(Player_ship) ) {
2402 control_used(TARGET_PREV);
2403 if ( hud_sensors_ok(Player_ship) ) {
2408 // target the next hostile target
2409 case TARGET_NEXT_CLOSEST_HOSTILE:
2410 control_used(TARGET_NEXT_CLOSEST_HOSTILE);
2411 if (hud_sensors_ok(Player_ship)){
2412 hud_target_next_list();
2416 // target the previous closest hostile
2417 case TARGET_PREV_CLOSEST_HOSTILE:
2418 control_used(TARGET_PREV_CLOSEST_HOSTILE);
2419 if (hud_sensors_ok(Player_ship)){
2420 hud_target_next_list(1,0);
2424 // toggle auto-targeting
2425 case TOGGLE_AUTO_TARGETING:
2426 control_used(TOGGLE_AUTO_TARGETING);
2427 hud_gauge_popup_start(HUD_AUTO_TARGET);
2428 Players[Player_num].flags ^= PLAYER_FLAGS_AUTO_TARGETING;
2429 if ( Players[Player_num].flags & PLAYER_FLAGS_AUTO_TARGETING ) {
2430 if (hud_sensors_ok(Player_ship)) {
2431 hud_target_closest(opposing_team_mask(Player_ship->team), -1, FALSE, TRUE );
2432 snd_play(&Snds[SND_SHIELD_XFER_OK], 1.0f);
2433 // HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Auto targeting activated", -1));
2435 Players[Player_num].flags ^= PLAYER_FLAGS_AUTO_TARGETING;
2438 snd_play(&Snds[SND_SHIELD_XFER_OK], 1.0f);
2439 // HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Auto targeting deactivated", -1));
2443 // target the next friendly ship
2444 case TARGET_NEXT_CLOSEST_FRIENDLY:
2445 control_used(TARGET_NEXT_CLOSEST_FRIENDLY);
2446 if (hud_sensors_ok(Player_ship)){
2447 hud_target_next_list(0);
2451 // target the closest friendly ship
2452 case TARGET_PREV_CLOSEST_FRIENDLY:
2453 control_used(TARGET_PREV_CLOSEST_FRIENDLY);
2454 if (hud_sensors_ok(Player_ship)) {
2455 hud_target_next_list(0,0);
2459 // target ship closest to center of reticle
2460 case TARGET_SHIP_IN_RETICLE:
2461 control_used(TARGET_SHIP_IN_RETICLE);
2462 if (hud_sensors_ok(Player_ship)){
2463 hud_target_in_reticle_new();
2468 case TARGET_LAST_TRANMISSION_SENDER:
2469 control_used(TARGET_LAST_TRANMISSION_SENDER);
2470 if ( hud_sensors_ok(Player_ship)) {
2471 hud_target_last_transmit();
2476 // target the closest repair ship
2477 case TARGET_CLOSEST_REPAIR_SHIP:
2478 control_used(TARGET_CLOSEST_REPAIR_SHIP);
2479 // AL: Try to find the closest repair ship coming to repair the player... if no support
2480 // ships are coming to rearm the player, just try for the closest repair ship
2481 if ( hud_target_closest_repair_ship(OBJ_INDEX(Player_obj)) == 0 ) {
2482 if ( hud_target_closest_repair_ship() == 0 ) {
2483 snd_play(&Snds[SND_TARGET_FAIL]);
2488 // target the closest ship attacking current target
2489 case TARGET_CLOSEST_SHIP_ATTACKING_TARGET:
2490 control_used(TARGET_CLOSEST_SHIP_ATTACKING_TARGET);
2491 if (hud_sensors_ok(Player_ship)){
2492 hud_target_closest(opposing_team_mask(Player_ship->team), Player_ai->target_objnum);
2496 // stop targeting ship
2497 case STOP_TARGETING_SHIP:
2498 control_used(STOP_TARGETING_SHIP);
2499 hud_cease_targeting();
2502 // target closest ship that is attacking player
2503 case TARGET_CLOSEST_SHIP_ATTACKING_SELF:
2504 control_used(TARGET_CLOSEST_SHIP_ATTACKING_SELF);
2505 if (hud_sensors_ok(Player_ship)){
2506 hud_target_closest(opposing_team_mask(Player_ship->team), OBJ_INDEX(Player_obj), TRUE, 0, 1);
2510 // target your target's target
2511 case TARGET_TARGETS_TARGET:
2512 control_used(TARGET_TARGETS_TARGET);
2513 if (hud_sensors_ok(Player_ship)){
2514 hud_target_targets_target();
2518 // target ships subsystem in reticle
2519 case TARGET_SUBOBJECT_IN_RETICLE:
2520 control_used(TARGET_SUBOBJECT_IN_RETICLE);
2521 if (hud_sensors_ok(Player_ship)){
2522 hud_target_subsystem_in_reticle();
2526 case TARGET_PREV_SUBOBJECT:
2527 control_used(TARGET_PREV_SUBOBJECT);
2528 if (hud_sensors_ok(Player_ship)){
2529 hud_target_prev_subobject();
2533 // target next subsystem on current target
2534 case TARGET_NEXT_SUBOBJECT:
2535 control_used(TARGET_NEXT_SUBOBJECT);
2536 if (hud_sensors_ok(Player_ship)){
2537 hud_target_next_subobject();
2541 // stop targeting subsystems on ship
2542 case STOP_TARGETING_SUBSYSTEM:
2543 control_used(STOP_TARGETING_SUBSYSTEM);
2544 hud_cease_subsystem_targeting();
2547 case TARGET_NEXT_BOMB:
2548 control_used(TARGET_NEXT_BOMB);
2549 hud_target_missile(Player_obj, 1);
2552 case TARGET_PREV_BOMB:
2553 control_used(TARGET_PREV_BOMB);
2554 hud_target_missile(Player_obj, 0);
2557 case TARGET_NEXT_UNINSPECTED_CARGO:
2558 hud_target_uninspected_object(1);
2561 case TARGET_PREV_UNINSPECTED_CARGO:
2562 hud_target_uninspected_object(0);
2565 case TARGET_NEWEST_SHIP:
2566 hud_target_newest_ship();
2569 case TARGET_NEXT_LIVE_TURRET:
2570 hud_target_live_turret(1);
2573 case TARGET_PREV_LIVE_TURRET:
2574 hud_target_live_turret(0);
2577 // wingman message: attack current target
2578 case ATTACK_MESSAGE:
2579 control_used(ATTACK_MESSAGE);
2580 hud_squadmsg_shortcut( ATTACK_TARGET_ITEM );
2583 // wingman message: disarm current target
2584 case DISARM_MESSAGE:
2585 control_used(DISARM_MESSAGE);
2586 hud_squadmsg_shortcut( DISARM_TARGET_ITEM );
2589 // wingman message: disable current target
2590 case DISABLE_MESSAGE:
2591 control_used(DISABLE_MESSAGE);
2592 hud_squadmsg_shortcut( DISABLE_TARGET_ITEM );
2595 // wingman message: disable current target
2596 case ATTACK_SUBSYSTEM_MESSAGE:
2597 control_used(ATTACK_SUBSYSTEM_MESSAGE);
2598 hud_squadmsg_shortcut( DISABLE_SUBSYSTEM_ITEM );
2601 // wingman message: capture current target
2602 case CAPTURE_MESSAGE:
2603 control_used(CAPTURE_MESSAGE);
2604 hud_squadmsg_shortcut( CAPTURE_TARGET_ITEM );
2607 // wingman message: engage enemy
2608 case ENGAGE_MESSAGE:
2609 control_used(ENGAGE_MESSAGE);
2610 hud_squadmsg_shortcut( ENGAGE_ENEMY_ITEM );
2613 // wingman message: form on my wing
2615 control_used(FORM_MESSAGE);
2616 hud_squadmsg_shortcut( FORMATION_ITEM );
2619 // wingman message: protect current target
2620 case PROTECT_MESSAGE:
2621 control_used(PROTECT_MESSAGE);
2622 hud_squadmsg_shortcut( PROTECT_TARGET_ITEM );
2625 // wingman message: cover me
2627 control_used(COVER_MESSAGE);
2628 hud_squadmsg_shortcut( COVER_ME_ITEM );
2631 // wingman message: warp out
2633 control_used(WARP_MESSAGE);
2634 hud_squadmsg_shortcut( DEPART_ITEM );
2637 case IGNORE_MESSAGE:
2638 control_used(IGNORE_MESSAGE);
2639 hud_squadmsg_shortcut( IGNORE_TARGET_ITEM );
2644 control_used(REARM_MESSAGE);
2645 hud_squadmsg_rearm_shortcut();
2648 // cycle to next radar range
2649 case RADAR_RANGE_CYCLE:
2650 control_used(RADAR_RANGE_CYCLE);
2651 HUD_config.rp_dist++;
2652 if ( HUD_config.rp_dist >= RR_MAX_RANGES )
2653 HUD_config.rp_dist = 0;
2655 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Radar range set to %s", 38), Radar_range_text(HUD_config.rp_dist));
2658 // toggle the squadmate messaging menu
2660 control_used(SQUADMSG_MENU);
2661 hud_squadmsg_toggle(); // leave the details to the messaging code!!!
2664 // show the mission goals screen
2666 control_used(SHOW_GOALS);
2667 gameseq_post_event( GS_EVENT_SHOW_GOALS );
2672 // in multiplayer, all end mission requests should go through the server
2673 if(Game_mode & GM_MULTIPLAYER){
2674 multi_handle_end_mission_request();
2678 control_used(END_MISSION);
2680 if (collide_predict_large_ship(Player_obj, 200.0f)) {
2681 gamesnd_play_iface(SND_GENERAL_FAIL);
2682 HUD_printf(XSTR( "** WARNING ** Collision danger. Warpout not activated.", 39));
2683 } else if (ship_get_subsystem_strength( Player_ship, SUBSYSTEM_ENGINE ) < 0.1f) {
2684 gamesnd_play_iface(SND_GENERAL_FAIL);
2685 HUD_printf(XSTR( "Engine failure. Cannot engage warp drive.", 40));
2687 gameseq_post_event( GS_EVENT_PLAYER_WARPOUT_START );
2691 case ADD_REMOVE_ESCORT:
2692 if ( Player_ai->target_objnum >= 0 ) {
2693 control_used(ADD_REMOVE_ESCORT);
2694 hud_add_remove_ship_escort(Player_ai->target_objnum);
2699 control_used(ESCORT_CLEAR);
2700 hud_escort_clear_all();
2703 case TARGET_NEXT_ESCORT_SHIP:
2704 control_used(TARGET_NEXT_ESCORT_SHIP);
2705 hud_escort_target_next();
2708 // increase weapon recharge rate
2709 case INCREASE_WEAPON:
2710 hud_gauge_popup_start(HUD_ETS_GAUGE);
2711 return button_function_critical(INCREASE_WEAPON);
2714 // decrease weapon recharge rate
2715 case DECREASE_WEAPON:
2716 hud_gauge_popup_start(HUD_ETS_GAUGE);
2717 return button_function_critical(DECREASE_WEAPON);
2720 // increase shield recharge rate
2721 case INCREASE_SHIELD:
2722 hud_gauge_popup_start(HUD_ETS_GAUGE);
2723 return button_function_critical(INCREASE_SHIELD);
2726 // decrease shield recharge rate
2727 case DECREASE_SHIELD:
2728 hud_gauge_popup_start(HUD_ETS_GAUGE);
2729 return button_function_critical(DECREASE_SHIELD);
2732 // increase energy to engines
2733 case INCREASE_ENGINE:
2734 hud_gauge_popup_start(HUD_ETS_GAUGE);
2735 return button_function_critical(INCREASE_ENGINE);
2738 // decrease energy to engines
2739 case DECREASE_ENGINE:
2740 hud_gauge_popup_start(HUD_ETS_GAUGE);
2741 return button_function_critical(DECREASE_ENGINE);
2746 hud_gauge_popup_start(HUD_ETS_GAUGE);
2747 return button_function_critical(ETS_EQUALIZE);
2751 // equalize shield energy to all quadrants
2752 case SHIELD_EQUALIZE:
2753 return button_function_critical(SHIELD_EQUALIZE);
2756 // transfer shield energy to front
2757 case SHIELD_XFER_TOP:
2758 return button_function_critical(SHIELD_XFER_TOP);
2761 // transfer shield energy to rear
2762 case SHIELD_XFER_BOTTOM:
2763 return button_function_critical(SHIELD_XFER_BOTTOM);
2766 // transfer shield energy to left
2767 case SHIELD_XFER_LEFT:
2768 return button_function_critical(SHIELD_XFER_LEFT);
2771 // transfer shield energy to right
2772 case SHIELD_XFER_RIGHT:
2773 return button_function_critical(SHIELD_XFER_RIGHT);
2776 // transfer energy to shield from weapons
2778 return button_function_critical(XFER_SHIELD);
2781 // transfer energy to weapons from shield
2783 return button_function_critical(XFER_LASER);
2786 // message all netplayers button
2787 case MULTI_MESSAGE_ALL:
2788 multi_msg_key_down(MULTI_MSG_ALL);
2791 // message all friendlies button
2792 case MULTI_MESSAGE_FRIENDLY:
2793 multi_msg_key_down(MULTI_MSG_FRIENDLY);
2796 // message all hostiles button
2797 case MULTI_MESSAGE_HOSTILE:
2798 multi_msg_key_down(MULTI_MSG_HOSTILE);
2801 // message targeted ship (if player)
2802 case MULTI_MESSAGE_TARGET:
2803 multi_msg_key_down(MULTI_MSG_TARGET);
2806 // if i'm an observer, zoom to my targeted object
2807 case MULTI_OBSERVER_ZOOM_TO:
2808 multi_obs_zoom_to_target();
2811 // toggle between high and low HUD contrast
2812 case TOGGLE_HUD_CONTRAST:
2813 gamesnd_play_iface(SND_USER_SELECT);
2814 hud_toggle_contrast();
2818 // toggle network info
2819 case MULTI_TOGGLE_NETINFO:
2820 extern int Multi_display_netinfo;
2821 Multi_display_netinfo = !Multi_display_netinfo;
2824 // self destruct (multiplayer only)
2825 case MULTI_SELF_DESTRUCT:
2826 if(!(Game_mode & GM_MULTIPLAYER)){
2831 if((Net_player == NULL) || (Net_player->player == NULL)){
2835 // blow myself up, if I'm the server
2836 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
2837 if((Net_player->player->objnum >= 0) && (Net_player->player->objnum < MAX_OBJECTS) &&
2838 (Objects[Net_player->player->objnum].type == OBJ_SHIP) && (Objects[Net_player->player->objnum].instance >= 0) && (Objects[Net_player->player->objnum].instance < MAX_SHIPS)){
2840 ship_self_destruct(&Objects[Net_player->player->objnum]);
2843 // otherwise send a packet to the server
2845 send_self_destruct_packet();
2850 // following are not handled here, but we need to bypass the Int3()
2851 case LAUNCH_COUNTERMEASURE:
2853 case ONE_THIRD_THROTTLE:
2854 case TWO_THIRDS_THROTTLE:
2855 case MINUS_5_PERCENT_THROTTLE:
2856 case PLUS_5_PERCENT_THROTTLE:
2869 // Call functions for when buttons are pressed
2870 void button_info_do(button_info *bi)
2874 for (i=0; i<NUM_BUTTON_FIELDS; i++) {
2875 if ( bi->status[i] == 0 ){
2879 // at least one bit is set in the status integer
2880 for (j=0; j<32; j++) {
2882 // check if the bit is set. If button_function returns 1 (implying the action was taken), then unset the bit
2883 if ( bi->status[i] & (1 << j) ) {
2884 // always process buttons which are valid for demo playback
2885 if(button_function_demo_valid(32 * i + j)){
2886 bi->status[i] &= ~(1 << j);
2890 // if we're in demo playback, always clear the bits
2891 if(Game_mode & GM_DEMO_PLAYBACK){
2892 bi->status[i] &= ~(1 << j);
2894 // otherwise check as normal
2895 else if (button_function(32 * i + j)) {
2896 bi->status[i] &= ~(1 << j);
2905 // set the bit for the corresponding action n (BUTTON_ #define from KeyControl.h)
2906 void button_info_set(button_info *bi, int n)
2908 int field_num, bit_num;
2913 bi->status[field_num] |= (1 << bit_num);
2916 // unset the bit for the corresponding action n (BUTTON_ #define from KeyControl.h)
2917 void button_info_unset(button_info *bi, int n)
2919 int field_num, bit_num;
2924 bi->status[field_num] &= ~(1 << bit_num);
2927 int button_info_query(button_info *bi, int n)
2929 return bi->status[n / 32] & (1 << (n % 32));
2932 // clear out the button_info struct
2933 void button_info_clear(button_info *bi)
2937 for (i=0; i<NUM_BUTTON_FIELDS; i++) {
2942 // strip out all noncritical keys from the button info struct
2943 void button_strip_noncritical_keys(button_info *bi)
2947 // clear out all noncritical keys
2948 for(idx=0;idx<Non_critical_key_set_size;idx++){
2949 button_info_unset(bi,Non_critical_key_set[idx]);