2 * $Logfile: /Freespace2/code/Io/KeyControl.cpp $
7 * Routines to read and deal with keyboard input.
10 * Revision 1.1 2002/05/03 03:28:09 root
14 * 47 9/09/99 11:40p Dave
15 * Handle an Assert() in beam code. Added supernova sounds. Play the right
16 * 2 end movies properly, based upon what the player did in the mission.
18 * 46 9/07/99 11:26p Andsager
19 * Fix "r" targeting key, making evaluate_ship_as_closest_target() and
20 * hud_target_live_turret() consider if turret is targeting player
22 * 45 9/03/99 1:31a Dave
23 * CD checking by act. Added support to play 2 cutscenes in a row
24 * seamlessly. Fixed super low level cfile bug related to files in the
25 * root directory of a CD. Added cheat code to set campaign mission # in
28 * 44 9/01/99 10:09a Dave
31 * 43 8/27/99 10:36a Dave
32 * Impose a 2% penalty for hitting the shield balance key.
34 * 42 8/27/99 9:57a Dave
35 * Enabled standard cheat codes. Allow player to continue in a campaing
36 * after using cheat codes.
38 * 41 8/26/99 9:45a Dave
39 * First pass at easter eggs and cheats.
41 * 40 8/24/99 1:49a Dave
42 * Fixed client-side afterburner stuttering. Added checkbox for no version
43 * checking on PXO join. Made button info passing more friendly between
46 * 39 8/22/99 5:53p Dave
47 * Scoring fixes. Added self destruct key. Put callsigns in the logfile
48 * instead of ship designations for multiplayer players.
50 * 38 8/19/99 10:59a Dave
51 * Packet loss detection.
53 * 37 8/18/99 12:09p Andsager
54 * Add debug if message has no anim for message. Make messages come from
57 * 36 8/05/99 2:05a Dave
60 * 35 8/01/99 12:39p Dave
61 * Added HUD contrast control key (for nebula).
63 * 34 7/31/99 2:30p Dave
64 * Added nifty mission message debug viewing keys.
66 * 33 7/21/99 8:10p Dave
67 * First run of supernova effect.
69 * 32 7/15/99 4:09p Andsager
70 * Disable cheats for FS2_DEMO
72 * 31 7/15/99 9:20a Andsager
73 * FS2_DEMO initial checkin
75 * 30 7/07/99 3:32p Dave
76 * Oops. Forgot to remove this.
78 * 29 7/02/99 4:31p Dave
79 * Much more sophisticated lightning support.
81 * 28 6/10/99 3:43p Dave
82 * Do a better job of syncing text colors to HUD gauges.
84 * 27 6/09/99 2:55p Andsager
85 * Allow multiple asteroid subtypes (of large, medium, small) and follow
88 * 26 5/24/99 5:45p Dave
89 * Added detail levels to the nebula, with a decent speedup. Split nebula
90 * lightning into its own section.
92 * 25 5/08/99 8:25p Dave
93 * Upped object pairs. First run of nebula lightning.
95 * 24 5/05/99 9:02p Dave
96 * Fixed D3D aabitmap rendering. Spiffed up nebula effect a bit (added
97 * rotations, tweaked values, made bitmap selection more random). Fixed
98 * D3D beam weapon clipping problem. Added D3d frame dumping.
100 * 23 5/03/99 9:07a Dave
101 * Pirate Bob. Changed beam test code a bit.
103 * 22 4/21/99 6:15p Dave
104 * Did some serious housecleaning in the beam code. Made it ready to go
105 * for anti-fighter "pulse" weapons. Fixed collision pair creation. Added
106 * a handy macro for recalculating collision pairs for a given object.
108 * 21 4/16/99 5:54p Dave
109 * Support for on/off style "stream" weapons. Real early support for
110 * target-painting lasers.
112 * 20 3/31/99 8:24p Dave
113 * Beefed up all kinds of stuff, incluging beam weapons, nebula effects
114 * and background nebulae. Added per-ship non-dimming pixel colors.
116 * 19 3/29/99 6:17p Dave
117 * More work on demo system. Got just about everything in except for
118 * blowing ships up, secondary weapons and player death/warpout.
120 * 18 3/28/99 5:58p Dave
121 * Added early demo code. Make objects move. Nice and framerate
122 * independant, but not much else. Don't use yet unless you're me :)
124 * 17 3/09/99 6:24p Dave
125 * More work on object update revamping. Identified several sources of
126 * unnecessary bandwidth.
128 * 16 2/21/99 6:01p Dave
129 * Fixed standalone WSS packets.
131 * 15 2/21/99 1:48p Dave
132 * Some code for monitoring datarate for multiplayer in detail.
134 * 14 1/21/99 2:06p Dave
135 * Final checkin for multiplayer testing.
137 * 13 1/19/99 3:57p Andsager
138 * Round 2 of variables
140 * 12 1/12/99 12:53a Dave
141 * More work on beam weapons - made collision detection very efficient -
142 * collide against all object types properly - made 3 movement types
143 * smooth. Put in test code to check for possible non-darkening pixels on
146 * 11 1/08/99 2:08p Dave
147 * Fixed software rendering for pofview. Super early support for AWACS and
150 * 10 12/06/98 2:36p Dave
151 * Drastically improved nebula fogging.
153 * 9 12/04/98 3:37p Andsager
154 * Added comment out asteroid launcher
156 * 8 11/19/98 4:19p Dave
157 * Put IPX sockets back in psnet. Consolidated all multiplayer config
160 * 7 11/05/98 5:55p Dave
161 * Big pass at reducing #includes
163 * 6 10/26/98 9:42a Dave
164 * Early flak gun support.
166 * 5 10/20/98 1:39p Andsager
167 * Make so sparks follow animated ship submodels. Modify
168 * ship_weapon_do_hit_stuff() and ship_apply_local_damage() to add
169 * submodel_num. Add submodel_num to multiplayer hit packet.
171 * 4 10/13/98 9:28a Dave
172 * Started neatening up freespace.h. Many variables renamed and
173 * reorganized. Added AlphaColors.[h,cpp]
175 * 3 10/09/98 2:57p Dave
176 * Starting splitting up OS stuff.
178 * 2 10/07/98 10:53a Dave
181 * 1 10/07/98 10:49a Dave
183 * 387 6/17/98 11:02a Lawrance
184 * show what cheat code is in the comment
186 * 386 6/09/98 5:15p Lawrance
187 * French/German localization
189 * 385 6/09/98 10:31a Hoffoss
190 * Created index numbers for all xstr() references. Any new xstr() stuff
191 * added from here on out should be added to the end if the list. The
192 * current list count can be found in FreeSpace.cpp (search for
195 * 384 6/01/98 11:43a John
196 * JAS & MK: Classified all strings for localization.
198 * 383 5/24/98 1:46p Mike
201 * 382 5/19/98 2:20p Mike
202 * Comment out nprintf().
204 * 381 5/19/98 12:19p Mike
207 * 380 5/19/98 11:11a Lawrance
208 * Make 'G' only target hostiles
210 * 379 5/18/98 11:00p Mike
211 * Adding support for cheat system.
213 * 378 5/18/98 12:41a Allender
214 * fixed subsystem problems on clients (i.e. not reporting properly on
215 * damage indicator). Fixed ingame join problem with respawns. minor
218 * 377 5/17/98 1:43a Dave
219 * Eradicated chatbox problems. Remove speed match for observers. Put in
220 * help screens for PXO. Fix messaging and end mission privelges. Fixed
221 * team select screen bugs. Misc UI fixes.
223 * 376 5/15/98 8:36p Lawrance
224 * Add 'target ship that last sent transmission' target key
226 * 375 5/14/98 11:07a Lawrance
227 * Ensure looped sounds get stopped before stopping all channels
229 * 374 5/12/98 11:59p Dave
230 * Put in some more functionality for Parallax Online.
232 * 373 5/11/98 5:29p Hoffoss
233 * Added mouse button mapped to joystick button support.
235 * 372 5/08/98 10:14a Lawrance
236 * Play sound when auto-targeting gets toggled.
238 * 371 5/04/98 9:25a Allender
239 * don't allow time compression in multiplayer
241 * 370 4/30/98 4:43p Allender
242 * trap player obj when changing dual fire status on ship
244 * 369 4/30/98 4:16p Peter
245 * fixes for critical button functions when a player (client) ship is dead
248 * 368 4/27/98 9:03a Dave
249 * Fixed a multiplayer sequencing bug where paused players who were in the
250 * options screen got an Assert when unpausing. Removed an optimiized
251 * build warning in keycontrol.
253 * 367 4/26/98 4:29p Lawrance
254 * Put back time compression keys... somehow they were trashed by a later
257 * 366 4/25/98 5:36p Mike
258 * Prevent player warpout if engine < 10%.
264 #include "linklist.h"
272 #include "contexthelp.h"
273 #include "gamesequence.h"
275 #include "missiongoals.h"
277 #include "hudtarget.h"
278 #include "optionsmenu.h"
279 #include "freespace.h"
280 #include "controlsconfig.h"
284 #include "multiutil.h"
289 #include "hudsquadmsg.h"
290 #include "eventmusic.h"
291 #include "animplay.h"
292 #include "freespace.h"
293 #include "cmeasure.h"
294 #include "missionhotkey.h"
295 #include "afterburner.h"
296 #include "missionparse.h"
297 #include "hudescort.h"
298 #include "hudshield.h"
299 #include "multiutil.h"
300 #include "multimsgs.h"
301 #include "keycontrol.h"
305 #include "hudobserver.h"
306 #include "missionlog.h"
307 #include "hudtargetbox.h"
309 #include "objcollide.h"
310 #include "hudconfig.h"
311 #include "missioncampaign.h"
313 #include "multi_respawn.h"
314 #include "multi_pmsg.h"
317 #include "multi_pause.h"
318 #include "multi_observer.h"
319 #include "multi_endgame.h"
321 #include "neblightning.h"
322 #include "supernova.h"
323 #include "missionmessage.h"
324 #include "mainhallmenu.h"
327 // --------------------------------------------------------------
329 // --------------------------------------------------------------
331 // --------------------------------------------------------------
333 // --------------------------------------------------------------
334 typedef struct asteroid_field {
335 vector min_bound; // Minimum range of field.
336 vector max_bound; // Maximum range of field.
337 vector vel; // Average asteroid moves at this velocity.
338 float speed; // Average speed of field
339 int num_initial_asteroids; // Number of asteroids at creation.
342 #define CHEAT_BUFFER_LEN 20
343 #define CHEATSPOT (CHEAT_BUFFER_LEN - 1)
345 char CheatBuffer[CHEAT_BUFFER_LEN+1];
348 char *Cheat_code_demo = NOX("33BE^(8]C01(:=BHt");
350 char *Cheat_code = NOX("33BE^(8]C01(:=BHt"); // www.freespace2.com
351 char *Cheat_code_fish = NOX("bDc9y+$;#AIDRoouM"); // vasudanswuvfishes
352 char *Cheat_code_headz = NOX("!;:::@>F7L?@@2:@A"); // humanheadsinside.
353 char *Cheat_code_tooled = NOX("sipp-^rM@L!U^usjX"); // tooledworkedowned
354 char *Cheat_code_pirate = NOX("MAP4YP[4=-2uC(yJ^"); // arrrrwalktheplank
355 char *Cheat_code_skip = NOX("7!ICkSI\"(8n3JesBP"); // skipmemymissionyo
357 // 666)6=N79+Z45=BE0e
358 int Tool_enabled = 0;
362 // list of the cheat codes
364 // "DavidPerry" NOX("0!XZQ*K.pu");
365 // NOX("&BvWJe=a?$VP*=@2W,2Y"); // Super-secret 20 character string!
366 //NOX("STs`nHqW\\lv#KD_aCSWN"); // solveditonceandforall (note double \\ as string contains \.
368 char *Cheat_code_in_game = NOX("///FES)P<A5=7CCB!n10"); // www.volition-inc.com
369 char *Cheat_code_movies = NOX("&BvWJe=a?$VP*=@2W,2Y"); // freespacestandsalone
370 char *Cheat_code_pirate = NOX("%,sPzoE>\\+_(Qs#+h-8o"); // arrwalktheplankmatey
375 int All_movies_enabled = 0;
377 //int Debug_allowed = 0;
381 extern int AI_watch_object;
382 extern int Countermeasures_enabled;
384 extern fix Game_time_compression;
386 extern float do_subobj_hit_stuff(object *ship_obj, object *other_obj, vector *hitpos, float damage);
388 extern void mission_goal_mark_all_true( int type );
390 int Normal_key_set[] = {
393 TARGET_NEXT_CLOSEST_HOSTILE,
394 TARGET_PREV_CLOSEST_HOSTILE,
395 TARGET_NEXT_CLOSEST_FRIENDLY,
396 TARGET_PREV_CLOSEST_FRIENDLY,
397 TARGET_TARGETS_TARGET,
398 TARGET_SHIP_IN_RETICLE,
399 TARGET_LAST_TRANMISSION_SENDER,
400 TARGET_CLOSEST_SHIP_ATTACKING_TARGET,
401 TARGET_CLOSEST_SHIP_ATTACKING_SELF,
403 TOGGLE_AUTO_TARGETING,
404 TARGET_SUBOBJECT_IN_RETICLE,
405 TARGET_PREV_SUBOBJECT,
406 TARGET_NEXT_SUBOBJECT,
407 STOP_TARGETING_SUBSYSTEM,
409 TARGET_NEXT_UNINSPECTED_CARGO,
410 TARGET_PREV_UNINSPECTED_CARGO,
412 TARGET_NEXT_LIVE_TURRET,
413 TARGET_PREV_LIVE_TURRET,
420 ATTACK_SUBSYSTEM_MESSAGE,
439 TARGET_NEXT_ESCORT_SHIP,
463 TOGGLE_AUTO_MATCH_TARGET_SPEED,
466 VIEW_EXTERNAL_TOGGLE_CAMERA_LOCK,
467 LAUNCH_COUNTERMEASURE,
470 PLUS_5_PERCENT_THROTTLE,
471 MINUS_5_PERCENT_THROTTLE,
475 TARGET_CLOSEST_REPAIR_SHIP,
478 MULTI_MESSAGE_FRIENDLY,
479 MULTI_MESSAGE_HOSTILE,
480 MULTI_MESSAGE_TARGET,
481 MULTI_OBSERVER_ZOOM_TO,
488 MULTI_TOGGLE_NETINFO,
492 int Dead_key_set[] = {
495 TARGET_NEXT_CLOSEST_HOSTILE,
496 TARGET_PREV_CLOSEST_HOSTILE,
497 TARGET_NEXT_CLOSEST_FRIENDLY,
498 TARGET_PREV_CLOSEST_FRIENDLY,
499 TARGET_TARGETS_TARGET,
500 TARGET_CLOSEST_SHIP_ATTACKING_TARGET,
502 TOGGLE_AUTO_TARGETING,
503 TARGET_SUBOBJECT_IN_RETICLE,
504 TARGET_PREV_SUBOBJECT,
505 TARGET_NEXT_SUBOBJECT,
506 STOP_TARGETING_SUBSYSTEM,
508 TARGET_NEXT_LIVE_TURRET,
509 TARGET_PREV_LIVE_TURRET,
520 TARGET_NEXT_ESCORT_SHIP,
521 TARGET_CLOSEST_REPAIR_SHIP,
524 MULTI_MESSAGE_FRIENDLY,
525 MULTI_MESSAGE_HOSTILE,
526 MULTI_MESSAGE_TARGET,
527 MULTI_OBSERVER_ZOOM_TO,
533 int Critical_key_set[] = {
552 int Non_critical_key_set[] = {
556 TOGGLE_AUTO_MATCH_TARGET_SPEED,
559 TARGET_NEXT_CLOSEST_HOSTILE,
560 TARGET_PREV_CLOSEST_HOSTILE,
561 TOGGLE_AUTO_TARGETING,
562 TARGET_NEXT_CLOSEST_FRIENDLY,
563 TARGET_PREV_CLOSEST_FRIENDLY,
564 TARGET_SHIP_IN_RETICLE,
565 TARGET_LAST_TRANMISSION_SENDER,
566 TARGET_CLOSEST_REPAIR_SHIP,
567 TARGET_CLOSEST_SHIP_ATTACKING_TARGET,
569 TARGET_CLOSEST_SHIP_ATTACKING_SELF,
570 TARGET_TARGETS_TARGET,
571 TARGET_SUBOBJECT_IN_RETICLE,
572 TARGET_PREV_SUBOBJECT,
573 TARGET_NEXT_SUBOBJECT,
574 STOP_TARGETING_SUBSYSTEM,
577 TARGET_NEXT_UNINSPECTED_CARGO,
578 TARGET_PREV_UNINSPECTED_CARGO,
580 TARGET_NEXT_LIVE_TURRET,
581 TARGET_PREV_LIVE_TURRET,
585 ATTACK_SUBSYSTEM_MESSAGE,
596 VIEW_EXTERNAL_TOGGLE_CAMERA_LOCK,
604 TARGET_NEXT_ESCORT_SHIP,
606 MULTI_MESSAGE_FRIENDLY,
607 MULTI_MESSAGE_HOSTILE,
608 MULTI_MESSAGE_TARGET,
609 MULTI_OBSERVER_ZOOM_TO,
612 MULTI_TOGGLE_NETINFO,
617 // set sizes of the key sets automatically
618 int Normal_key_set_size = sizeof(Normal_key_set) / sizeof(int);
619 int Dead_key_set_size = sizeof(Dead_key_set) / sizeof(int);
620 int Critical_key_set_size = sizeof(Critical_key_set) / sizeof(int);
621 int Non_critical_key_set_size = sizeof(Non_critical_key_set) / sizeof(int);
623 // --------------------------------------------------------------
624 // routine to process keys used only for debugging
625 // --------------------------------------------------------------
628 void debug_cycle_player_ship(int delta)
630 if ( Player_obj == NULL )
633 int si_index = Ships[Player_obj->instance].ship_info_index;
638 if ( si_index > MAX_SHIP_TYPES ){
642 si_index = MAX_SHIP_TYPES - 1;
644 sip = &Ship_info[si_index];
645 if ( sip->flags & SIF_PLAYER_SHIP ){
651 if ( sanity > MAX_SHIP_TYPES ){
656 change_ship_type(Player_obj->instance, si_index);
657 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Player ship changed to %s", 0), Ship_info[si_index].name);
660 // cycle targeted ship to next ship in that species
661 void debug_cycle_targeted_ship(int delta)
665 int si_index, species;
666 char name[NAME_LENGTH];
668 if ( Player_ai->target_objnum == -1 )
671 objp = &Objects[Player_ai->target_objnum];
672 if ( objp->type != OBJ_SHIP )
675 si_index = Ships[objp->instance].ship_info_index;
676 Assert(si_index != -1 );
677 species = Ship_info[si_index].species;
683 if ( si_index > MAX_SHIP_TYPES )
686 si_index = MAX_SHIP_TYPES-1;
689 sip = &Ship_info[si_index];
691 // if it has test in the name, jump over it
692 strcpy(name, sip->name);
694 if ( strstr(name,NOX("test")) != NULL )
697 if ( sip->species == species && (sip->flags & (SIF_FIGHTER | SIF_BOMBER | SIF_TRANSPORT) ) )
702 if ( sanity > MAX_SHIP_TYPES )
706 change_ship_type(objp->instance, si_index);
707 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Changed player target to %s", 1), Ship_info[si_index].name);
710 void debug_max_secondary_weapons(object *objp)
713 ship *shipp = &Ships[objp->instance];
714 ship_info *sip = &Ship_info[shipp->ship_info_index];
716 for ( index = 0; index < MAX_SECONDARY_BANKS; index++ ) {
717 shipp->weapons.secondary_bank_ammo[index] = sip->secondary_bank_ammo_capacity[index];
721 void debug_change_song(int delta)
724 if ( event_music_next_soundtrack(delta) != -1 ) {
725 event_music_get_soundtrack_name(buf);
726 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Soundtrack changed to: %s", 2), buf);
729 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Event music is not playing", 3));
733 //extern void set_global_ignore_object(int objnum);
735 extern void hud_target_asteroid();
736 extern int Framerate_delay;
738 extern void snd_stop_any_sound();
740 void process_debug_keys(int k)
743 if ( !Debug_allowed )
747 // if ( (k & KEY_DEBUGGED) && (Game_mode & GM_RECORDING_DEMO) )
751 case KEY_DEBUGGED + KEY_H:
752 hud_target_toggle_hidden_from_sensors();
755 case KEY_DEBUGGED + KEY_F:
758 for (i=0; i<NUM_HUD_GAUGES; i++) {
759 hud_gauge_start_flash(i);
762 extern int wacky_scheme;
763 if(wacky_scheme == 3){
770 case KEY_DEBUGGED + KEY_ALTED + KEY_F:
771 Framerate_delay += 10;
772 HUD_printf(XSTR( "Framerate delay increased to %i milliseconds per frame.", 4), Framerate_delay);
775 case KEY_DEBUGGED + KEY_ALTED + KEY_SHIFTED + KEY_F:
776 Framerate_delay -= 10;
777 if (Framerate_delay < 0)
780 HUD_printf(XSTR( "Framerate delay decreased to %i milliseconds per frame.", 5), Framerate_delay);
783 case KEY_DEBUGGED + KEY_C:
784 case KEY_DEBUGGED1 + KEY_C:
785 // hud_enemymsg_toggle();
786 if(Player_obj->flags & OF_COLLIDES){
787 obj_set_flags(Player_obj, Player_obj->flags & ~(OF_COLLIDES));
788 HUD_sourced_printf(HUD_SOURCE_HIDDEN, "Player no longer collides");
790 obj_set_flags(Player_obj, Player_obj->flags | OF_COLLIDES);
791 HUD_sourced_printf(HUD_SOURCE_HIDDEN, "Player collides");
795 case KEY_DEBUGGED + KEY_SHIFTED + KEY_C:
796 case KEY_DEBUGGED1 + KEY_SHIFTED + KEY_C:
797 Countermeasures_enabled = !Countermeasures_enabled;
798 HUD_printf(XSTR( "Countermeasure firing: %s", 6), Countermeasures_enabled ? XSTR( "ENABLED", 7) : XSTR( "DISABLED", 8));
801 case KEY_DEBUGGED + KEY_E:
802 gameseq_post_event(GS_EVENT_EVENT_DEBUG);
805 case KEY_DEBUGGED + KEY_COMMA:
806 if ( Game_time_compression > (F1_0/4) ){ // can't compress below 0.25
807 Game_time_compression /= 2;
810 case KEY_DEBUGGED + KEY_PERIOD:
811 if ( Game_time_compression < (F1_0*8) ){
812 Game_time_compression *= 2;
816 // Kill! the currently targeted ship.
817 case KEY_DEBUGGED + KEY_K:
818 case KEY_DEBUGGED1 + KEY_K:
819 if (Player_ai->target_objnum != -1) {
820 object *objp = &Objects[Player_ai->target_objnum];
822 switch (objp->type) {
824 ship_apply_local_damage( objp, Player_obj, &objp->pos, 100000.0f, MISS_SHIELDS, CREATE_SPARKS);
825 ship_apply_local_damage( objp, Player_obj, &objp->pos, 1.0f, MISS_SHIELDS, CREATE_SPARKS);
828 Weapons[objp->instance].lifeleft = 0.01f;
835 // play the next mission message
836 case KEY_DEBUGGED + KEY_V:
837 extern int Message_debug_index;
838 extern int Num_messages_playing;
839 // stop any other messages
840 if(Num_messages_playing){
845 if(Message_debug_index >= Num_messages - 1){
846 Message_debug_index = Num_builtin_messages;
848 Message_debug_index++;
852 message_send_unique_to_player( Messages[Message_debug_index].name, Message_waves[Messages[Message_debug_index].wave_info.index].name, MESSAGE_SOURCE_SPECIAL, MESSAGE_PRIORITY_HIGH, 0, 0 );
853 if (Messages[Message_debug_index].avi_info.index == -1) {
854 HUD_printf("No anim set for message \"%s\"; None will play!", Messages[Message_debug_index].name);
858 // play the previous mission message
859 case KEY_DEBUGGED + KEY_SHIFTED + KEY_V:
860 extern int Message_debug_index;
861 extern int Num_messages_playing;
862 // stop any other messages
863 if(Num_messages_playing){
867 // go maybe go down one
868 if(Message_debug_index == Num_builtin_messages - 1){
869 Message_debug_index = Num_builtin_messages;
870 } else if(Message_debug_index > Num_builtin_messages){
871 Message_debug_index--;
875 message_send_unique_to_player( Messages[Message_debug_index].name, Message_waves[Messages[Message_debug_index].wave_info.index].name, MESSAGE_SOURCE_SPECIAL, MESSAGE_PRIORITY_HIGH, 0, 0 );
876 if (Messages[Message_debug_index].avi_info.index == -1) {
877 HUD_printf("No avi associated with this message; None will play!");
881 // reset to the beginning of mission messages
882 case KEY_DEBUGGED + KEY_ALTED + KEY_V:
883 extern int Message_debug_index;
884 Message_debug_index = Num_builtin_messages - 1;
885 HUD_printf("Resetting to first mission message");
888 // Kill! the currently targeted ship.
889 case KEY_DEBUGGED + KEY_ALTED + KEY_SHIFTED + KEY_K:
890 case KEY_DEBUGGED1 + KEY_ALTED + KEY_SHIFTED + KEY_K:
891 if (Player_ai->target_objnum != -1) {
892 object *objp = &Objects[Player_ai->target_objnum];
894 if (objp->type == OBJ_SHIP) {
895 ship_apply_local_damage( objp, Player_obj, &objp->pos, Ship_info[Ships[objp->instance].ship_info_index].initial_hull_strength * 0.1f + 10.0f, MISS_SHIELDS, CREATE_SPARKS);
900 // Kill the currently targeted subsystem.
901 case KEY_DEBUGGED + KEY_SHIFTED + KEY_K:
902 case KEY_DEBUGGED1 + KEY_SHIFTED + KEY_K:
903 if ((Player_ai->target_objnum != -1) && (Player_ai->targeted_subsys != NULL)) {
904 object *objp = &Objects[Player_ai->target_objnum];
905 if ( objp->type == OBJ_SHIP ) {
906 ship *sp = &Ships[objp->instance];
909 get_subsystem_world_pos(objp, Player_ai->targeted_subsys, &g_subobj_pos);
911 do_subobj_hit_stuff(objp, Player_obj, &g_subobj_pos, (float) -Player_ai->targeted_subsys->system_info->type); //100.0f);
913 if ( sp->subsys_info[SUBSYSTEM_ENGINE].current_hits <= 0.0f ) {
914 mission_log_add_entry(LOG_SHIP_DISABLED, sp->ship_name, NULL );
915 sp->flags |= SF_DISABLED; // add the disabled flag
918 if ( sp->subsys_info[SUBSYSTEM_TURRET].current_hits <= 0.0f ) {
919 mission_log_add_entry(LOG_SHIP_DISARMED, sp->ship_name, NULL );
920 // sp->flags |= SF_DISARMED; // add the disarmed flag
926 case KEY_DEBUGGED + KEY_ALTED + KEY_K:
927 case KEY_DEBUGGED1 + KEY_ALTED + KEY_K:
929 float shield, integrity;
932 vm_vec_rand_vec_quick(&randvec);
933 vm_vec_scale_add(&pos, &Player_obj->pos, &randvec, Player_obj->radius);
934 ship_apply_local_damage(Player_obj, Player_obj, &pos, 25.0f, MISS_SHIELDS, CREATE_SPARKS);
935 hud_get_target_strength(Player_obj, &shield, &integrity);
936 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "You knocked yourself down to %7.3f percent hull.\n", 9), 100.0f * integrity);
940 // Whack down the player's shield and hull by a little more than 50%
941 // Select next object to be viewed by AI.
942 case KEY_DEBUGGED + KEY_I:
943 case KEY_DEBUGGED1 + KEY_I:
944 Player_obj->flags ^= OF_INVULNERABLE;
945 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "You are %s", 10), Player_obj->flags & OF_INVULNERABLE ? XSTR( "now INVULNERABLE!", 11) : XSTR( "no longer invulnerable...", 12));
948 case KEY_DEBUGGED + KEY_SHIFTED + KEY_I:
949 case KEY_DEBUGGED1 + KEY_SHIFTED + KEY_I:
950 if (Player_ai->target_objnum != -1) {
951 object *objp = &Objects[Player_ai->target_objnum];
953 objp->flags ^= OF_INVULNERABLE;
954 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Player's target [%s] is %s", 13), Ships[objp->instance].ship_name, objp->flags & OF_INVULNERABLE ? XSTR( "now INVULNERABLE!", 11) : XSTR( "no longer invulnerable...", 12));
958 case KEY_DEBUGGED + KEY_ALTED + KEY_I:
959 if (Player_ai->target_objnum != -1)
960 set_global_ignore_object(Player_ai->target_objnum);
964 case KEY_DEBUGGED + KEY_N:
966 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Spewing debug info about object #%d", 14), AI_watch_object);
969 case KEY_DEBUGGED + KEY_O:
970 // case KEY_DEBUGGED1 + KEY_O:
971 toggle_player_object();
974 case KEY_DEBUGGED + KEY_SHIFTED + KEY_O:
975 extern int Debug_octant;
976 if(Debug_octant == 7){
981 nprintf(("General", "Debug_octant == %d\n", Debug_octant));
984 case KEY_DEBUGGED + KEY_P:
988 case KEY_DEBUGGED + KEY_W:
989 case KEY_DEBUGGED1 + KEY_W:
990 case KEY_DEBUGGED + KEY_SHIFTED + KEY_W:
991 case KEY_DEBUGGED1 + KEY_SHIFTED + KEY_W:
992 // temp code for testing purposes, toggles weapon energy cheat
993 Weapon_energy_cheat = !Weapon_energy_cheat;
994 if (Weapon_energy_cheat) {
996 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Weapon energy and missile count will always be at full ALL SHIPS!", 15));
998 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Weapon energy and missile count will always be at full for player", 16));
1000 debug_max_secondary_weapons(Player_obj);
1001 if (k & KEY_SHIFTED) {
1004 for ( objp = GET_FIRST(&obj_used_list); objp !=END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp) )
1005 if (objp->type == OBJ_SHIP)
1006 debug_max_secondary_weapons(objp);
1010 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Normal weapon energy system / missile count restored", 17));
1014 case KEY_DEBUGGED + KEY_G:
1015 // case KEY_DEBUGGED1 + KEY_G:
1016 mission_goal_mark_all_true( PRIMARY_GOAL );
1019 case KEY_DEBUGGED + KEY_G + KEY_SHIFTED:
1020 // case KEY_DEBUGGED1 + KEY_G + KEY_SHIFTED:
1021 mission_goal_mark_all_true( SECONDARY_GOAL );
1024 case KEY_DEBUGGED + KEY_G + KEY_ALTED:
1025 // case KEY_DEBUGGED1 + KEY_G + KEY_ALTED:
1026 mission_goal_mark_all_true( BONUS_GOAL );
1029 case KEY_DEBUGGED + KEY_9: {
1030 case KEY_DEBUGGED1 + KEY_9:
1033 shipp = &Ships[Player_obj->instance];
1034 shipp->weapons.secondary_bank_weapons[shipp->weapons.current_secondary_bank]++;
1035 if ( shipp->weapons.secondary_bank_weapons[shipp->weapons.current_secondary_bank] >= Num_weapon_types )
1036 shipp->weapons.secondary_bank_weapons[shipp->weapons.current_secondary_bank] = First_secondary_index;
1038 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Secondary Weapon forced to %s", 18), Weapon_info[shipp->weapons.secondary_bank_weapons[shipp->weapons.current_secondary_bank]].name);
1043 case KEY_DEBUGGED + KEY_SHIFTED + KEY_9: {
1044 case KEY_DEBUGGED1 + KEY_SHIFTED + KEY_9:
1047 shipp = &Ships[Player_obj->instance];
1048 shipp->weapons.secondary_bank_weapons[shipp->weapons.current_secondary_bank]--;
1049 if ( shipp->weapons.secondary_bank_weapons[shipp->weapons.current_secondary_bank] < 0)
1050 shipp->weapons.secondary_bank_weapons[shipp->weapons.current_secondary_bank] = Num_weapon_types - 1;
1052 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Secondary Weapon forced to %s", 18), Weapon_info[shipp->weapons.secondary_bank_weapons[shipp->weapons.current_secondary_bank]].name);
1058 case KEY_DEBUGGED + KEY_U: {
1059 case KEY_DEBUGGED1 + KEY_U:
1061 extern asteroid_field Asteroid_field;
1062 object *asteroid_create(asteroid_field *asfieldp, int asteroid_type, int subtype);
1063 object *objp = asteroid_create(&Asteroid_field, 0, 0);
1065 vm_vec_copy_scale(&vel, &Player_obj->orient.fvec, 50.0f);
1066 objp->phys_info.vel = vel;
1067 objp->phys_info.desired_vel = vel;
1068 objp->pos = Player_obj->pos;
1069 //mission_goal_mark_all_true( PRIMARY_GOAL );
1074 case KEY_DEBUGGED + KEY_0: {
1075 case KEY_DEBUGGED1 + KEY_0:
1078 shipp = &Ships[Player_obj->instance];
1079 shipp->weapons.primary_bank_weapons[shipp->weapons.current_primary_bank]++;
1080 if ( shipp->weapons.primary_bank_weapons[shipp->weapons.current_primary_bank] >= First_secondary_index )
1081 shipp->weapons.primary_bank_weapons[shipp->weapons.current_primary_bank] = 0;
1083 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Primary Weapon forced to %s", 19), Weapon_info[shipp->weapons.primary_bank_weapons[shipp->weapons.current_primary_bank]].name);
1087 case KEY_DEBUGGED + KEY_SHIFTED + KEY_0: {
1088 case KEY_DEBUGGED1 + KEY_SHIFTED + KEY_0:
1091 shipp = &Ships[Player_obj->instance];
1092 shipp->weapons.primary_bank_weapons[shipp->weapons.current_primary_bank]--;
1093 if ( shipp->weapons.primary_bank_weapons[shipp->weapons.current_primary_bank] < 0)
1094 shipp->weapons.primary_bank_weapons[shipp->weapons.current_primary_bank] = First_secondary_index-1 ;
1096 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Primary Weapon forced to %s", 19), Weapon_info[shipp->weapons.primary_bank_weapons[shipp->weapons.current_primary_bank]].name);
1100 case KEY_DEBUGGED + KEY_J: {
1101 int new_pattern = event_music_return_current_pattern();
1104 if ( new_pattern >= MAX_PATTERNS )
1107 event_music_change_pattern(new_pattern);
1111 case KEY_DEBUGGED + KEY_M: {
1112 if ( Event_music_enabled ) {
1113 event_music_disable();
1114 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Event music disabled", 20));
1117 event_music_enable();
1118 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Event music enabled", 21));
1124 case KEY_DEBUGGED + KEY_R: {
1125 // case KEY_DEBUGGED1 + KEY_R:
1126 if (Player_ai->target_objnum != -1)
1127 ai_issue_rearm_request(&Objects[Player_ai->target_objnum]);
1129 ai_issue_rearm_request(Player_obj);
1134 case KEY_DEBUGGED + KEY_SHIFTED + KEY_UP:
1135 Game_detail_level++;
1136 HUD_printf( XSTR( "Detail level set to %+d\n", 22), Game_detail_level );
1139 case KEY_DEBUGGED + KEY_SHIFTED + KEY_DOWN:
1140 Game_detail_level--;
1141 HUD_printf( XSTR( "Detail level set to %+d\n", 22), Game_detail_level );
1145 case KEY_DEBUGGED + KEY_SHIFTED + KEY_T: {
1146 extern int Test_begin;
1148 if ( Test_begin == 1 )
1152 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Frame Rate test started", 23));
1157 case KEY_DEBUGGED + KEY_D:
1158 extern int OO_update_index;
1160 if(MULTIPLAYER_MASTER){
1163 } while((OO_update_index < (MAX_PLAYERS-1)) && !MULTI_CONNECTED(Net_players[OO_update_index]));
1164 if(OO_update_index >= MAX_PLAYERS-1){
1165 OO_update_index = -1;
1168 if(OO_update_index < 0){
1169 OO_update_index = MY_NET_PLAYER_NUM;
1171 OO_update_index = -1;
1176 // change player ship to next flyable type
1177 case KEY_DEBUGGED + KEY_RIGHT:
1178 debug_cycle_player_ship(1);
1181 // change player ship to previous flyable ship
1182 case KEY_DEBUGGED + KEY_LEFT:
1183 debug_cycle_player_ship(-1);
1186 // cycle target to ship
1187 case KEY_DEBUGGED + KEY_SHIFTED + KEY_RIGHT:
1188 debug_cycle_targeted_ship(1);
1191 // cycle target to previous ship
1192 case KEY_DEBUGGED + KEY_SHIFTED + KEY_LEFT:
1193 debug_cycle_targeted_ship(-1);
1196 // change species of the targeted ship
1197 case KEY_DEBUGGED + KEY_S: {
1198 if ( Player_ai->target_objnum < 0 )
1204 objp = &Objects[Player_ai->target_objnum];
1205 if ( objp->type != OBJ_SHIP )
1208 sip = &Ship_info[Ships[objp->instance].ship_info_index];
1210 if ( sip->species > SPECIES_SHIVAN )
1213 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Species of target changed to: %s", 24), Species_names[sip->species]);
1217 case KEY_DEBUGGED + KEY_SHIFTED + KEY_S:
1218 game_increase_skill_level();
1219 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Skill level set to %s.", 25), Skill_level_names(Game_skill_level));
1222 // kill all missiles
1223 case KEY_DEBUGGED + KEY_SHIFTED + KEY_1:
1226 case KEY_DEBUGGED + KEY_SHIFTED + KEY_2:
1229 case KEY_DEBUGGED + KEY_SHIFTED + KEY_3:
1232 case KEY_DEBUGGED + KEY_SHIFTED + KEY_4:
1235 case KEY_DEBUGGED + KEY_SHIFTED + KEY_5:
1238 case KEY_DEBUGGED + KEY_SHIFTED + KEY_6:
1241 case KEY_DEBUGGED + KEY_SHIFTED + KEY_7:
1244 case KEY_DEBUGGED + KEY_SHIFTED + KEY_8:
1247 case KEY_DEBUGGED + KEY_SHIFTED + KEY_9:
1251 case KEY_DEBUGGED + KEY_CTRLED + KEY_1:
1254 case KEY_DEBUGGED + KEY_CTRLED + KEY_2:
1257 case KEY_DEBUGGED + KEY_CTRLED + KEY_3:
1261 case KEY_DEBUGGED + KEY_T: {
1263 event_music_get_info(buf);
1264 HUD_sourced_printf(HUD_SOURCE_HIDDEN, buf);
1268 case KEY_DEBUGGED + KEY_UP:
1269 debug_change_song(1);
1272 case KEY_DEBUGGED + KEY_DOWN:
1273 debug_change_song(-1);
1276 case KEY_PADMINUS: {
1279 if ( keyd_pressed[KEY_1] ) {
1284 if ( keyd_pressed[KEY_2] ) {
1286 HUD_color_green -= 4;
1289 if ( keyd_pressed[KEY_3] ) {
1291 HUD_color_blue -= 4;
1300 case KEY_DEBUGGED + KEY_Y:
1302 // blast a debug lightning bolt in front of the player
1303 vector start, strike;
1305 vm_vec_scale_add(&start, &Player_obj->pos, &Player_obj->orient.fvec, 300.0f);
1306 vm_vec_scale_add2(&start, &Player_obj->orient.rvec, -300.0f);
1307 vm_vec_scale_add(&strike, &start, &Player_obj->orient.rvec, 600.0f);
1308 nebl_bolt(DEBUG_BOLT, &start, &strike);
1317 if ( keyd_pressed[KEY_1] ) {
1322 if ( keyd_pressed[KEY_2] ) {
1324 HUD_color_green += 4;
1327 if ( keyd_pressed[KEY_3] ) {
1329 HUD_color_blue += 4;
1342 void ppsk_hotkeys(int k)
1347 // use k to check for keys that can have Shift,Ctrl,Alt,Del status
1351 k &= ~KEY_DEBUGGED; // since hitting F11 will set this bit
1363 hotkey_set = mission_hotkey_get_set_num(k);
1364 if ( !(Players[Player_num].flags & PLAYER_FLAGS_MSG_MODE) )
1365 hud_target_hotkey_select( hotkey_set );
1367 hud_squadmsg_hotkey_select( hotkey_set );
1371 case KEY_F5 + KEY_SHIFTED:
1372 case KEY_F6 + KEY_SHIFTED:
1373 case KEY_F7 + KEY_SHIFTED:
1374 case KEY_F8 + KEY_SHIFTED:
1375 case KEY_F9 + KEY_SHIFTED:
1376 case KEY_F10 + KEY_SHIFTED:
1377 case KEY_F11 + KEY_SHIFTED:
1378 case KEY_F12 + KEY_SHIFTED:
1379 hotkey_set = mission_hotkey_get_set_num(k&(~KEY_SHIFTED));
1380 mprintf(("Adding to set %d\n", hotkey_set+1));
1381 if ( Player_ai->target_objnum == -1)
1382 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "No target to add/remove from set %d.", 26), hotkey_set+1);
1384 hud_target_hotkey_add_remove( hotkey_set, &Objects[Player_ai->target_objnum], HOTKEY_USER_ADDED);
1385 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "%s added to set %d. (F%d)", 27), Ships[Objects[Player_ai->target_objnum].instance].ship_name, hotkey_set, 4+hotkey_set+1);
1390 case KEY_F5 + KEY_SHIFTED + KEY_ALTED:
1391 case KEY_F6 + KEY_SHIFTED + KEY_ALTED:
1392 case KEY_F7 + KEY_SHIFTED + KEY_ALTED:
1393 case KEY_F8 + KEY_SHIFTED + KEY_ALTED:
1394 case KEY_F9 + KEY_SHIFTED + KEY_ALTED:
1395 case KEY_F10 + KEY_SHIFTED + KEY_ALTED:
1396 case KEY_F11 + KEY_SHIFTED + KEY_ALTED:
1397 case KEY_F12 + KEY_SHIFTED + KEY_ALTED:
1398 hotkey_set = mission_hotkey_get_set_num(k & ~KEY_SHIFTED+KEY_ALTED);
1399 hud_target_hotkey_clear( hotkey_set );
1402 case KEY_SHIFTED + KEY_MINUS:
1403 if ( HUD_color_alpha > HUD_COLOR_ALPHA_USER_MIN ) {
1408 /* case KEY_SHIFTED + KEY_U:
1410 object *debris_create(object *source_obj, int model_num, int submodel_num, vector *pos, vector *exp_center, int hull_flag, float exp_force);
1412 object *temp = debris_create(Player_obj, Ships[0].modelnum, model_get(Ships[0].modelnum)->debris_objects[0], &Player_obj->pos, &Player_obj->pos, 1, 1.0f);
1414 temp->hull_strength = 5000.0f;
1415 int objnum = temp - Objects;
1416 vm_vec_copy_scale(&Objects[objnum].phys_info.vel, &Player_obj->orient.fvec, 30.0f);
1422 case KEY_SHIFTED + KEY_EQUAL:
1423 if ( HUD_color_alpha < HUD_COLOR_ALPHA_USER_MAX ) {
1434 // check keypress 'key' against a set of valid controls and mark the match in the
1435 // player's button info bitfield. Also checks joystick controls in the set.
1437 // key = scancode (plus modifiers).
1438 // count = total size of the list
1439 // list = list of Control_config struct action indices to check for
1440 void process_set_of_keys(int key, int count, int *list)
1444 for (i=0; i<count; i++)
1445 if (check_control(list[i], key))
1446 button_info_set(&Player->bi, list[i]);
1449 // routine to process keys used for player ship stuff (*not* ship movement).
1450 void process_player_ship_keys(int k)
1454 masked_k = k & ~KEY_CTRLED; // take out CTRL modifier only
1456 // moved this line to beginning of function since hotkeys now encompass
1457 // F5 - F12. We can return after using F11 as a hotkey.
1458 ppsk_hotkeys(masked_k);
1459 if (keyd_pressed[KEY_DEBUG_KEY]){
1463 // if we're in supernova mode. do nothing
1464 if(Player->control_mode == PCM_SUPERNOVA){
1468 // pass the key to the squadmate messaging code. If the messaging code took the key, then return
1469 // from here immediately since we don't want to do further key processing.
1470 if ( hud_squadmsg_read_key(k) )
1473 if ( Player->control_mode == PCM_NORMAL ) {
1474 // The following things are not legal to do while dead.
1475 if ( !(Game_mode & GM_DEAD) ) {
1476 process_set_of_keys(masked_k, Normal_key_set_size, Normal_key_set);
1478 process_set_of_keys(masked_k, Dead_key_set_size, Dead_key_set);
1485 // Handler for when player hits 'ESC' during the game
1486 void game_do_end_mission_popup()
1488 int pf_flags, choice;
1489 // char savegame_filename[_MAX_FNAME];
1491 // do the multiplayer version of this
1492 if(Game_mode & GM_MULTIPLAYER){
1493 multi_quit_game(PROMPT_ALL);
1496 // single player version....
1497 // do housekeeping things.
1499 game_stop_looped_sounds();
1502 pf_flags = PF_BODY_BIG | PF_USE_AFFIRMATIVE_ICON | PF_USE_NEGATIVE_ICON;
1503 choice = popup(pf_flags, 3, POPUP_NO, XSTR( "&Yes, Quit", 28), XSTR( "Yes, &Restart", 29), XSTR( "Do you really want to end the mission?", 30));
1507 // save the game before quitting if in campaign mode
1508 // MWA -- 3/26/98 -- no more save/restore!!!!
1510 if ( Game_mode & GM_CAMPAIGN_MODE ) {
1511 memset(savegame_filename, 0, _MAX_FNAME);
1512 mission_campaign_savefile_generate_root(savegame_filename);
1513 strcat(savegame_filename, NOX("svg"));
1514 if ( state_save_all(savegame_filename) ) {
1515 Int3(); // could not save this game
1519 gameseq_post_event(GS_EVENT_END_GAME);
1523 gameseq_post_event(GS_EVENT_ENTER_GAME);
1527 break; // do nothing
1535 // handle pause keypress
1536 void game_process_pause_key()
1538 // special processing for multiplayer
1539 if (Game_mode & GM_MULTIPLAYER) {
1540 if(Multi_pause_status){
1541 multi_pause_request(0);
1543 multi_pause_request(1);
1546 gameseq_post_event( GS_EVENT_PAUSE_GAME );
1550 #define WITHIN_BBOX() do { \
1551 float scale = 2.0f; \
1552 polymodel *pm = model_get(s_check->modelnum); \
1555 vector temp = new_obj->pos; \
1557 vm_vec_sub2(&temp, &hit_check->pos); \
1558 vm_vec_rotate(&gpos, &temp, &hit_check->orient); \
1559 if((gpos.x >= pm->mins.x * scale) && (gpos.y >= pm->mins.y * scale) && (gpos.z >= pm->mins.z * scale) && (gpos.x <= pm->maxs.x * scale) && (gpos.y <= pm->maxs.y * scale) && (gpos.z <= pm->maxs.z * scale)) { \
1565 #define MOVE_AWAY_BBOX() do { \
1566 polymodel *pm = model_get(s_check->modelnum); \
1568 switch((int)frand_range(0.0f, 3.9f)){ \
1570 new_obj->pos.x += 200.0f; \
1573 new_obj->pos.x -= 200.0f; \
1576 new_obj->pos.y += 200.0f; \
1579 new_obj->pos.y -= 200.0f; \
1582 new_obj->pos.z -= 200.0f; \
1588 // process cheat codes
1589 void game_process_cheats(int k)
1598 // no cheats in multiplayer, ever
1599 if(Game_mode & GM_MULTIPLAYER){
1604 k = key_to_ascii(k);
1606 for (i = 0; i < CHEAT_BUFFER_LEN; i++){
1607 CheatBuffer[i]=CheatBuffer[i+1];
1610 CheatBuffer[CHEATSPOT]=(char)k;
1612 cryptstring=jcrypt(&CheatBuffer[CHEAT_BUFFER_LEN - CRYPT_STRING_LENGTH]);
1615 if ( !strcmp(Cheat_code_demo, cryptstring) ) {
1616 HUD_printf(XSTR( "Cheats enabled.", 31));
1618 if (Player->flags & PLAYER_FLAGS_MSG_MODE){
1619 hud_squadmsg_toggle();
1624 if( !strcmp(Cheat_code, cryptstring) && !(Game_mode & GM_MULTIPLAYER)){
1626 HUD_printf("Cheats enabled");
1628 if( !strcmp(Cheat_code_fish, cryptstring) ){
1629 // only enable in the main hall
1630 if((gameseq_get_state() == GS_STATE_MAIN_MENU) && (main_hall_id() == 1)){
1631 extern void fishtank_start();
1635 if( !strcmp(Cheat_code_headz, cryptstring) ){
1636 main_hall_vasudan_funny();
1638 if( !strcmp(Cheat_code_skip, cryptstring) && (gameseq_get_state() == GS_STATE_MAIN_MENU)){
1639 extern void main_hall_campaign_cheat();
1640 main_hall_campaign_cheat();
1642 if( !strcmp(Cheat_code_tooled, cryptstring) && (Game_mode & GM_IN_MISSION)){
1644 HUD_printf("Prepare to be taken to school");
1646 if( !strcmp(Cheat_code_pirate, cryptstring) && (Game_mode & GM_IN_MISSION) && (Player_obj != NULL)){
1647 HUD_printf(NOX("Walk the plank"));
1649 for(int idx=0; idx<1; idx++){
1650 vector add = Player_obj->pos;
1651 add.x += frand_range(-700.0f, 700.0f);
1652 add.y += frand_range(-700.0f, 700.0f);
1653 add.z += frand_range(-700.0f, 700.0f);
1655 int objnum = ship_create(&vmd_identity_matrix, &add, Num_ship_types - 1);
1662 object *new_obj = &Objects[objnum];
1665 // now make sure we're not colliding with anyone
1668 moveup = GET_FIRST(&Ship_obj_list);
1669 while(moveup!=END_OF_LIST(&Ship_obj_list)){
1670 // don't check the new_obj itself!!
1671 if(moveup->objnum != objnum){
1672 hit_check = &Objects[moveup->objnum];
1673 Assert(hit_check->type == OBJ_SHIP);
1674 Assert(hit_check->instance >= 0);
1675 if((hit_check->type != OBJ_SHIP) || (hit_check->instance < 0)){
1678 s_check = &Ships[hit_check->instance];
1680 // just to make sure we don't get any strange magnitude errors
1681 if(vm_vec_same(&hit_check->pos, &Objects[objnum].pos)){
1682 Objects[objnum].pos.x += 1.0f;
1692 moveup = GET_NEXT(moveup);
1697 shipfx_warpin_start(&Objects[objnum]);
1699 // tell him to attack
1700 // ai_add_ship_goal_player( AIG_TYPE_PLAYER_SHIP, AI_GOAL_CHASE_ANY, SM_ATTACK, NULL, &Ai_info[Ships[Objects[objnum].instance].ai_index] );
1706 //#ifdef INTERPLAYQA
1707 if ( !strcmp(Cheat_code_in_game, cryptstring) ) {
1708 HUD_printf(XSTR( "Cheats enabled.", 31));
1710 if (Player->flags & PLAYER_FLAGS_MSG_MODE){
1711 hud_squadmsg_toggle();
1713 } else if ( !strcmp(Cheat_code_movies, cryptstring) ) {
1714 HUD_printf(XSTR( "All movies available in Tech Room", 32));
1715 All_movies_enabled = 1;
1716 if (Player->flags & PLAYER_FLAGS_MSG_MODE){
1717 hud_squadmsg_toggle();
1719 } else if( !strcmp(Cheat_code_pirate, cryptstring) ){
1720 HUD_printf(NOX("Walk the plank"));
1722 for(int idx=0; idx<1; idx++){
1724 add.x = frand_range(-1000.0f, 1000.0f);
1725 add.y = frand_range(-1000.0f, 1000.0f);
1726 add.z = frand_range(-1000.0f, 1000.0f);
1728 int objnum = ship_create(&vmd_identity_matrix, &add, Num_ship_types - 1);
1731 shipfx_warpin_start(&Objects[objnum]);
1739 void game_process_keys()
1743 button_info_clear(&Player->bi); // clear out the button info struct for the player
1747 // AL 12-10-97: Scan for keys used to leave the dead state (don't process any)
1748 // DB 1-13-98 : New popup code will run the game do state, so we must skip
1749 // all key processing in this function, since everything should be run through the popup dialog
1750 if ( Game_mode & GM_DEAD_BLEW_UP ) {
1754 game_process_cheats( k );
1756 // mwa -- 4/5/97 Moved these two function calls before the switch statement. I don't think
1757 // that this has adverse affect on anything and is acutally desireable because of the
1758 // ESC key being used to quit any HUD message/input mode that might be currently in use
1759 process_player_ship_keys(k);
1762 process_debug_keys(k); // Note, also processed for cheats.
1771 if ( Player->control_mode != PCM_NORMAL ) {
1772 if ( Player->control_mode == PCM_WARPOUT_STAGE1 ) {
1773 gameseq_post_event( GS_EVENT_PLAYER_WARPOUT_STOP );
1775 // too late to abort warp out!
1778 // let the ESC key break out of messaging mode
1779 if ( Players[Player_num].flags & PLAYER_FLAGS_MSG_MODE ) {
1780 hud_squadmsg_toggle();
1784 // if in external view or chase view, go back to cockpit view
1785 if ( Viewer_mode & (VM_EXTERNAL|VM_CHASE|VM_OTHER_SHIP) ) {
1786 Viewer_mode &= ~(VM_EXTERNAL|VM_CHASE|VM_OTHER_SHIP);
1790 if (!(Game_mode & GM_DEAD_DIED))
1791 game_do_end_mission_popup();
1802 case KEY_ALTED + KEY_SHIFTED+KEY_J:
1803 // treat the current joystick position as the center position
1807 case KEY_DEBUGGED | KEY_PAUSE:
1808 gameseq_post_event( GS_EVENT_DEBUG_PAUSE_GAME );
1812 game_process_pause_key();
1817 button_info_do(&Player->bi); // call functions based on status of button_info bit vectors
1820 int button_function_critical(int n, net_player *p = NULL)
1825 int at_self; // flag indicating the object is local (for hud messages, etc)
1829 // multiplayer clients should leave critical button bits alone and pass them to the server instead
1830 if ((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER)) {
1831 // if this flag is set, we should apply the button itself (came from the server)
1832 if (!Multi_button_info_ok){
1837 // in single player mode make sure we're using the player object and the player himself, otherwise use the object and
1838 // player pertaining to the passed net_player
1843 if(Game_mode & GM_MULTIPLAYER){
1846 // if we're the server in multiplayer and we're an observer, don't process our own critical button functions
1847 if((Net_player->flags & NETINFO_FLAG_AM_MASTER) && (Net_player->flags & NETINFO_FLAG_OBSERVER)){
1853 objp = &Objects[p->player->objnum];
1858 if ( NETPLAYER_IS_DEAD(npl) || (Ships[Objects[pl->objnum].instance].flags & SF_DYING) )
1863 // cycle to next secondary weapon
1864 case CYCLE_SECONDARY:
1866 control_used(CYCLE_SECONDARY);
1868 hud_gauge_popup_start(HUD_WEAPONS_GAUGE);
1869 if (ship_select_next_secondary(objp)) {
1870 ship* shipp = &Ships[objp->instance];
1871 if ( timestamp_elapsed(shipp->weapons.next_secondary_fire_stamp[shipp->weapons.current_secondary_bank]) ) {
1872 shipp->weapons.next_secondary_fire_stamp[shipp->weapons.current_secondary_bank] = timestamp(250); // 1/4 second delay until can fire
1875 // multiplayer server should maintain bank/link status here
1876 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
1877 Assert(npl != NULL);
1878 multi_server_update_player_weapons(npl,shipp);
1883 // cycle number of missiles
1884 case CYCLE_NUM_MISSLES:
1886 control_used(CYCLE_NUM_MISSLES);
1888 if ( objp == Player_obj ) {
1889 if ( Player_ship->weapons.num_secondary_banks <= 0 ) {
1890 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "This ship has no secondary weapons", 33));
1891 gamesnd_play_iface(SND_GENERAL_FAIL);
1896 if ( Ships[objp->instance].flags & SF_SECONDARY_DUAL_FIRE ) {
1897 Ships[objp->instance].flags &= ~SF_SECONDARY_DUAL_FIRE;
1899 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Secondary weapon set to normal fire mode", 34));
1900 snd_play( &Snds[SND_SECONDARY_CYCLE] );
1901 hud_gauge_popup_start(HUD_WEAPONS_GAUGE);
1904 Ships[objp->instance].flags |= SF_SECONDARY_DUAL_FIRE;
1906 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Secondary weapon set to dual fire mode", 35));
1907 snd_play( &Snds[SND_SECONDARY_CYCLE] );
1908 hud_gauge_popup_start(HUD_WEAPONS_GAUGE);
1912 // multiplayer server should maintain bank/link status here
1913 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
1914 Assert(npl != NULL);
1915 multi_server_update_player_weapons(npl,&Ships[objp->instance]);
1919 // increase weapon recharge rate
1920 case INCREASE_WEAPON:
1922 control_used(INCREASE_WEAPON);
1923 increase_recharge_rate(objp, WEAPONS);
1925 // multiplayer server should maintain bank/link status here
1926 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
1927 Assert(npl != NULL);
1928 multi_server_update_player_weapons(npl,&Ships[objp->instance]);
1932 // decrease weapon recharge rate
1933 case DECREASE_WEAPON:
1935 control_used(DECREASE_WEAPON);
1936 decrease_recharge_rate(objp, WEAPONS);
1938 // multiplayer server should maintain bank/link status here
1939 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
1940 Assert(npl != NULL);
1941 multi_server_update_player_weapons(npl,&Ships[objp->instance]);
1945 // increase shield recharge rate
1946 case INCREASE_SHIELD:
1948 control_used(INCREASE_SHIELD);
1949 increase_recharge_rate(objp, SHIELDS);
1951 // multiplayer server should maintain bank/link status here
1952 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
1953 Assert(npl != NULL);
1954 multi_server_update_player_weapons(npl,&Ships[objp->instance]);
1958 // decrease shield recharge rate
1959 case DECREASE_SHIELD:
1961 control_used(DECREASE_SHIELD);
1962 decrease_recharge_rate(objp, SHIELDS);
1964 // multiplayer server should maintain bank/link status here
1965 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
1966 Assert(npl != NULL);
1967 multi_server_update_player_weapons(npl,&Ships[objp->instance]);
1971 // increase energy to engines
1972 case INCREASE_ENGINE:
1974 control_used(INCREASE_ENGINE);
1975 increase_recharge_rate(objp, ENGINES);
1977 // multiplayer server should maintain bank/link status here
1978 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
1979 Assert(npl != NULL);
1980 multi_server_update_player_weapons(npl,&Ships[objp->instance]);
1984 // decrease energy to engines
1985 case DECREASE_ENGINE:
1987 control_used(DECREASE_ENGINE);
1988 decrease_recharge_rate(objp, ENGINES);
1990 // multiplayer server should maintain bank/link status here
1991 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
1992 Assert(npl != NULL);
1993 multi_server_update_player_weapons(npl,&Ships[objp->instance]);
1997 // equalize recharge rates
2000 control_used(ETS_EQUALIZE);
2003 set_default_recharge_rates(objp);
2004 snd_play( &Snds[SND_ENERGY_TRANS] );
2005 // multiplayer server should maintain bank/link status here
2006 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
2007 Assert(npl != NULL);
2008 multi_server_update_player_weapons(npl,&Ships[objp->instance]);
2012 // equalize shield energy to all quadrants
2013 case SHIELD_EQUALIZE:
2015 control_used(SHIELD_EQUALIZE);
2017 hud_shield_equalize(objp, pl);
2020 // transfer shield energy to front
2021 case SHIELD_XFER_TOP:
2023 control_used(SHIELD_XFER_TOP);
2025 hud_augment_shield_quadrant(objp, 1);
2028 // transfer shield energy to rear
2029 case SHIELD_XFER_BOTTOM:
2031 control_used(SHIELD_XFER_BOTTOM);
2032 hud_augment_shield_quadrant(objp, 2);
2035 // transfer shield energy to left
2036 case SHIELD_XFER_LEFT:
2038 control_used(SHIELD_XFER_LEFT);
2039 hud_augment_shield_quadrant(objp, 3);
2042 // transfer shield energy to right
2043 case SHIELD_XFER_RIGHT:
2045 control_used(SHIELD_XFER_RIGHT);
2046 hud_augment_shield_quadrant(objp, 0);
2049 // transfer energy to shield from weapons
2052 control_used(XFER_SHIELD);
2053 transfer_energy_to_shields(objp);
2056 // transfer energy to weapons from shield
2059 control_used(XFER_LASER);
2060 transfer_energy_to_weapons(objp);
2063 // following are not handled here, but we need to bypass the Int3()
2064 case LAUNCH_COUNTERMEASURE:
2067 case VIEW_EXTERNAL_TOGGLE_CAMERA_LOCK:
2068 case ONE_THIRD_THROTTLE:
2069 case TWO_THIRDS_THROTTLE:
2070 case MINUS_5_PERCENT_THROTTLE:
2071 case PLUS_5_PERCENT_THROTTLE:
2077 Int3(); // bad bad bad
2084 // return !0 if the action is allowed, otherwise return 0
2085 int button_allowed(int n)
2087 if ( hud_disabled() ) {
2091 case CYCLE_NEXT_PRIMARY:
2092 case CYCLE_PREV_PRIMARY:
2093 case CYCLE_SECONDARY:
2094 case ONE_THIRD_THROTTLE:
2095 case TWO_THIRDS_THROTTLE:
2096 case PLUS_5_PERCENT_THROTTLE:
2097 case MINUS_5_PERCENT_THROTTLE:
2109 // execute function corresponding to action n
2110 // basically, these are actions which don't affect demo playback at all
2111 int button_function_demo_valid(int n)
2113 // by default, we'll return "not processed". ret will get set to 1, if this is one of the keys which is always allowed, even in demo
2117 // No keys, not even targeting keys, when player in death roll. He can press keys after he blows up.
2118 if (Game_mode & GM_DEAD_DIED){
2122 // any of these buttons are valid
2125 control_used(VIEW_CHASE);
2126 Viewer_mode ^= VM_CHASE;
2127 if ( Viewer_mode & VM_CHASE ) {
2128 Viewer_mode &= ~VM_EXTERNAL;
2134 control_used(VIEW_EXTERNAL);
2135 Viewer_mode ^= VM_EXTERNAL;
2136 Viewer_mode &= ~VM_EXTERNAL_CAMERA_LOCKED; // reset camera lock when leave/entering external view
2137 if ( Viewer_mode & VM_EXTERNAL ) {
2138 Viewer_mode &= ~VM_CHASE;
2143 case VIEW_EXTERNAL_TOGGLE_CAMERA_LOCK:
2144 control_used(VIEW_EXTERNAL_TOGGLE_CAMERA_LOCK);
2145 if ( Viewer_mode & VM_EXTERNAL ) {
2146 Viewer_mode ^= VM_EXTERNAL_CAMERA_LOCKED;
2147 if ( Viewer_mode & VM_EXTERNAL_CAMERA_LOCKED ) {
2148 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "External camera is locked, controls will move ship", 36));
2150 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "External camera is free, controls will move the camera, not the ship", 37));
2156 case VIEW_OTHER_SHIP:
2157 control_used(VIEW_OTHER_SHIP);
2158 if ( Player_ai->target_objnum < 0 ) {
2159 snd_play( &Snds[SND_TARGET_FAIL] );
2161 if ( Objects[Player_ai->target_objnum].type != OBJ_SHIP ) {
2162 snd_play( &Snds[SND_TARGET_FAIL] );
2164 Viewer_mode ^= VM_OTHER_SHIP;
2170 case TIME_SLOW_DOWN:
2171 if ( Game_mode & GM_NORMAL ) {
2172 if ( Game_time_compression > F1_0) {
2173 Game_time_compression /= 2;
2175 gamesnd_play_error_beep();
2178 gamesnd_play_error_beep();
2184 if ( Game_mode & GM_NORMAL ) {
2185 if ( Game_time_compression < (F1_0*4) ) {
2186 Game_time_compression *= 2;
2188 gamesnd_play_error_beep();
2191 gamesnd_play_error_beep();
2201 // execute function corresponding to action n (BUTTON_ #define from KeyControl.h)
2202 int button_function(int n)
2206 if ( !button_allowed(n) ) {
2210 // No keys, not even targeting keys, when player in death roll. He can press keys after he blows up.
2211 if (Game_mode & GM_DEAD_DIED){
2216 // cycle to next primary weapon
2217 case CYCLE_NEXT_PRIMARY:
2219 if((Player_obj == NULL) || (Player_ship == NULL)){
2223 hud_gauge_popup_start(HUD_WEAPONS_GAUGE);
2224 if (ship_select_next_primary(Player_obj, CYCLE_PRIMARY_NEXT)) {
2225 ship* shipp = Player_ship;
2226 shipp->weapons.next_primary_fire_stamp[shipp->weapons.current_primary_bank] = timestamp(250); // 1/4 second delay until can fire
2227 // multiplayer server should maintain bank/link status here
2228 // if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
2229 // Assert(npl != NULL);
2230 // multi_server_update_player_weapons(npl,shipp);
2235 // cycle to previous primary weapon
2236 case CYCLE_PREV_PRIMARY:
2238 if((Player_obj == NULL) || (Player_ship == NULL)){
2242 hud_gauge_popup_start(HUD_WEAPONS_GAUGE);
2243 if (ship_select_next_primary(Player_obj, CYCLE_PRIMARY_PREV)) {
2244 ship* shipp = Player_ship;
2245 shipp->weapons.next_primary_fire_stamp[shipp->weapons.current_primary_bank] = timestamp(250); // 1/4 second delay until can fire
2247 // multiplayer server should maintain bank/link status here
2248 // if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
2249 // Assert(npl != NULL);
2250 // multi_server_update_player_weapons(npl,shipp);
2255 // cycle to next secondary weapon
2256 case CYCLE_SECONDARY:
2257 return button_function_critical(CYCLE_SECONDARY);
2260 // cycle number of missiles fired from secondary bank
2261 case CYCLE_NUM_MISSLES:
2262 return button_function_critical(CYCLE_NUM_MISSLES);
2265 // undefined in multiplayer for clients right now
2266 // match target speed
2267 case MATCH_TARGET_SPEED:
2268 control_used(MATCH_TARGET_SPEED);
2269 // If player is auto-matching, break auto-match speed
2270 if ( Player->flags & PLAYER_FLAGS_AUTO_MATCH_SPEED ) {
2271 Player->flags &= ~PLAYER_FLAGS_AUTO_MATCH_SPEED;
2273 player_match_target_speed();
2276 // undefined in multiplayer for clients right now
2277 // toggle auto-match target speed
2278 case TOGGLE_AUTO_MATCH_TARGET_SPEED:
2279 // multiplayer observers can't match target speed
2280 if((Game_mode & GM_MULTIPLAYER) && (Net_player != NULL) && ((Net_player->flags & NETINFO_FLAG_OBSERVER) || (Player_obj->type == OBJ_OBSERVER)) ){
2284 Player->flags ^= PLAYER_FLAGS_AUTO_MATCH_SPEED;
2285 control_used(TOGGLE_AUTO_MATCH_TARGET_SPEED);
2286 hud_gauge_popup_start(HUD_AUTO_SPEED);
2287 if ( Players[Player_num].flags & PLAYER_FLAGS_AUTO_MATCH_SPEED ) {
2288 snd_play(&Snds[SND_SHIELD_XFER_OK], 1.0f);
2289 // HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Auto match target speed activated", -1));
2290 if ( !Player->flags & PLAYER_FLAGS_MATCH_TARGET ) {
2291 player_match_target_speed();
2295 // HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Auto match target deactivated", -1));
2296 snd_play(&Snds[SND_SHIELD_XFER_OK], 1.0f);
2297 player_match_target_speed();
2303 control_used(TARGET_NEXT);
2304 if ( hud_sensors_ok(Player_ship) ) {
2311 control_used(TARGET_PREV);
2312 if ( hud_sensors_ok(Player_ship) ) {
2317 // target the next hostile target
2318 case TARGET_NEXT_CLOSEST_HOSTILE:
2319 control_used(TARGET_NEXT_CLOSEST_HOSTILE);
2320 if (hud_sensors_ok(Player_ship)){
2321 hud_target_next_list();
2325 // target the previous closest hostile
2326 case TARGET_PREV_CLOSEST_HOSTILE:
2327 control_used(TARGET_PREV_CLOSEST_HOSTILE);
2328 if (hud_sensors_ok(Player_ship)){
2329 hud_target_next_list(1,0);
2333 // toggle auto-targeting
2334 case TOGGLE_AUTO_TARGETING:
2335 control_used(TOGGLE_AUTO_TARGETING);
2336 hud_gauge_popup_start(HUD_AUTO_TARGET);
2337 Players[Player_num].flags ^= PLAYER_FLAGS_AUTO_TARGETING;
2338 if ( Players[Player_num].flags & PLAYER_FLAGS_AUTO_TARGETING ) {
2339 if (hud_sensors_ok(Player_ship)) {
2340 hud_target_closest(opposing_team_mask(Player_ship->team), -1, FALSE, TRUE );
2341 snd_play(&Snds[SND_SHIELD_XFER_OK], 1.0f);
2342 // HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Auto targeting activated", -1));
2344 Players[Player_num].flags ^= PLAYER_FLAGS_AUTO_TARGETING;
2347 snd_play(&Snds[SND_SHIELD_XFER_OK], 1.0f);
2348 // HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Auto targeting deactivated", -1));
2352 // target the next friendly ship
2353 case TARGET_NEXT_CLOSEST_FRIENDLY:
2354 control_used(TARGET_NEXT_CLOSEST_FRIENDLY);
2355 if (hud_sensors_ok(Player_ship)){
2356 hud_target_next_list(0);
2360 // target the closest friendly ship
2361 case TARGET_PREV_CLOSEST_FRIENDLY:
2362 control_used(TARGET_PREV_CLOSEST_FRIENDLY);
2363 if (hud_sensors_ok(Player_ship)) {
2364 hud_target_next_list(0,0);
2368 // target ship closest to center of reticle
2369 case TARGET_SHIP_IN_RETICLE:
2370 control_used(TARGET_SHIP_IN_RETICLE);
2371 if (hud_sensors_ok(Player_ship)){
2372 hud_target_in_reticle_new();
2376 case TARGET_LAST_TRANMISSION_SENDER:
2377 control_used(TARGET_LAST_TRANMISSION_SENDER);
2378 if ( hud_sensors_ok(Player_ship)) {
2379 hud_target_last_transmit();
2383 // target the closest repair ship
2384 case TARGET_CLOSEST_REPAIR_SHIP:
2385 control_used(TARGET_CLOSEST_REPAIR_SHIP);
2386 // AL: Try to find the closest repair ship coming to repair the player... if no support
2387 // ships are coming to rearm the player, just try for the closest repair ship
2388 if ( hud_target_closest_repair_ship(OBJ_INDEX(Player_obj)) == 0 ) {
2389 if ( hud_target_closest_repair_ship() == 0 ) {
2390 snd_play(&Snds[SND_TARGET_FAIL]);
2395 // target the closest ship attacking current target
2396 case TARGET_CLOSEST_SHIP_ATTACKING_TARGET:
2397 control_used(TARGET_CLOSEST_SHIP_ATTACKING_TARGET);
2398 if (hud_sensors_ok(Player_ship)){
2399 hud_target_closest(opposing_team_mask(Player_ship->team), Player_ai->target_objnum);
2403 // stop targeting ship
2404 case STOP_TARGETING_SHIP:
2405 control_used(STOP_TARGETING_SHIP);
2406 hud_cease_targeting();
2409 // target closest ship that is attacking player
2410 case TARGET_CLOSEST_SHIP_ATTACKING_SELF:
2411 control_used(TARGET_CLOSEST_SHIP_ATTACKING_SELF);
2412 if (hud_sensors_ok(Player_ship)){
2413 hud_target_closest(opposing_team_mask(Player_ship->team), OBJ_INDEX(Player_obj), TRUE, 0, 1);
2417 // target your target's target
2418 case TARGET_TARGETS_TARGET:
2419 control_used(TARGET_TARGETS_TARGET);
2420 if (hud_sensors_ok(Player_ship)){
2421 hud_target_targets_target();
2425 // target ships subsystem in reticle
2426 case TARGET_SUBOBJECT_IN_RETICLE:
2427 control_used(TARGET_SUBOBJECT_IN_RETICLE);
2428 if (hud_sensors_ok(Player_ship)){
2429 hud_target_subsystem_in_reticle();
2433 case TARGET_PREV_SUBOBJECT:
2434 control_used(TARGET_PREV_SUBOBJECT);
2435 if (hud_sensors_ok(Player_ship)){
2436 hud_target_prev_subobject();
2440 // target next subsystem on current target
2441 case TARGET_NEXT_SUBOBJECT:
2442 control_used(TARGET_NEXT_SUBOBJECT);
2443 if (hud_sensors_ok(Player_ship)){
2444 hud_target_next_subobject();
2448 // stop targeting subsystems on ship
2449 case STOP_TARGETING_SUBSYSTEM:
2450 control_used(STOP_TARGETING_SUBSYSTEM);
2451 hud_cease_subsystem_targeting();
2454 case TARGET_NEXT_BOMB:
2455 control_used(TARGET_NEXT_BOMB);
2456 hud_target_missile(Player_obj, 1);
2459 case TARGET_PREV_BOMB:
2460 control_used(TARGET_PREV_BOMB);
2461 hud_target_missile(Player_obj, 0);
2464 case TARGET_NEXT_UNINSPECTED_CARGO:
2465 hud_target_uninspected_object(1);
2468 case TARGET_PREV_UNINSPECTED_CARGO:
2469 hud_target_uninspected_object(0);
2472 case TARGET_NEWEST_SHIP:
2473 hud_target_newest_ship();
2476 case TARGET_NEXT_LIVE_TURRET:
2477 hud_target_live_turret(1);
2480 case TARGET_PREV_LIVE_TURRET:
2481 hud_target_live_turret(0);
2484 // wingman message: attack current target
2485 case ATTACK_MESSAGE:
2486 control_used(ATTACK_MESSAGE);
2487 hud_squadmsg_shortcut( ATTACK_TARGET_ITEM );
2490 // wingman message: disarm current target
2491 case DISARM_MESSAGE:
2492 control_used(DISARM_MESSAGE);
2493 hud_squadmsg_shortcut( DISARM_TARGET_ITEM );
2496 // wingman message: disable current target
2497 case DISABLE_MESSAGE:
2498 control_used(DISABLE_MESSAGE);
2499 hud_squadmsg_shortcut( DISABLE_TARGET_ITEM );
2502 // wingman message: disable current target
2503 case ATTACK_SUBSYSTEM_MESSAGE:
2504 control_used(ATTACK_SUBSYSTEM_MESSAGE);
2505 hud_squadmsg_shortcut( DISABLE_SUBSYSTEM_ITEM );
2508 // wingman message: capture current target
2509 case CAPTURE_MESSAGE:
2510 control_used(CAPTURE_MESSAGE);
2511 hud_squadmsg_shortcut( CAPTURE_TARGET_ITEM );
2514 // wingman message: engage enemy
2515 case ENGAGE_MESSAGE:
2516 control_used(ENGAGE_MESSAGE);
2517 hud_squadmsg_shortcut( ENGAGE_ENEMY_ITEM );
2520 // wingman message: form on my wing
2522 control_used(FORM_MESSAGE);
2523 hud_squadmsg_shortcut( FORMATION_ITEM );
2526 // wingman message: protect current target
2527 case PROTECT_MESSAGE:
2528 control_used(PROTECT_MESSAGE);
2529 hud_squadmsg_shortcut( PROTECT_TARGET_ITEM );
2532 // wingman message: cover me
2534 control_used(COVER_MESSAGE);
2535 hud_squadmsg_shortcut( COVER_ME_ITEM );
2538 // wingman message: warp out
2540 control_used(WARP_MESSAGE);
2541 hud_squadmsg_shortcut( DEPART_ITEM );
2544 case IGNORE_MESSAGE:
2545 control_used(IGNORE_MESSAGE);
2546 hud_squadmsg_shortcut( IGNORE_TARGET_ITEM );
2551 control_used(REARM_MESSAGE);
2552 hud_squadmsg_rearm_shortcut();
2555 // cycle to next radar range
2556 case RADAR_RANGE_CYCLE:
2557 control_used(RADAR_RANGE_CYCLE);
2558 HUD_config.rp_dist++;
2559 if ( HUD_config.rp_dist >= RR_MAX_RANGES )
2560 HUD_config.rp_dist = 0;
2562 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Radar range set to %s", 38), Radar_range_text(HUD_config.rp_dist));
2565 // toggle the squadmate messaging menu
2567 control_used(SQUADMSG_MENU);
2568 hud_squadmsg_toggle(); // leave the details to the messaging code!!!
2571 // show the mission goals screen
2573 control_used(SHOW_GOALS);
2574 gameseq_post_event( GS_EVENT_SHOW_GOALS );
2579 // in multiplayer, all end mission requests should go through the server
2580 if(Game_mode & GM_MULTIPLAYER){
2581 multi_handle_end_mission_request();
2585 control_used(END_MISSION);
2587 if (collide_predict_large_ship(Player_obj, 200.0f)) {
2588 gamesnd_play_iface(SND_GENERAL_FAIL);
2589 HUD_printf(XSTR( "** WARNING ** Collision danger. Warpout not activated.", 39));
2590 } else if (ship_get_subsystem_strength( Player_ship, SUBSYSTEM_ENGINE ) < 0.1f) {
2591 gamesnd_play_iface(SND_GENERAL_FAIL);
2592 HUD_printf(XSTR( "Engine failure. Cannot engage warp drive.", 40));
2594 gameseq_post_event( GS_EVENT_PLAYER_WARPOUT_START );
2598 case ADD_REMOVE_ESCORT:
2599 if ( Player_ai->target_objnum >= 0 ) {
2600 control_used(ADD_REMOVE_ESCORT);
2601 hud_add_remove_ship_escort(Player_ai->target_objnum);
2606 control_used(ESCORT_CLEAR);
2607 hud_escort_clear_all();
2610 case TARGET_NEXT_ESCORT_SHIP:
2611 control_used(TARGET_NEXT_ESCORT_SHIP);
2612 hud_escort_target_next();
2615 // increase weapon recharge rate
2616 case INCREASE_WEAPON:
2617 hud_gauge_popup_start(HUD_ETS_GAUGE);
2618 return button_function_critical(INCREASE_WEAPON);
2621 // decrease weapon recharge rate
2622 case DECREASE_WEAPON:
2623 hud_gauge_popup_start(HUD_ETS_GAUGE);
2624 return button_function_critical(DECREASE_WEAPON);
2627 // increase shield recharge rate
2628 case INCREASE_SHIELD:
2629 hud_gauge_popup_start(HUD_ETS_GAUGE);
2630 return button_function_critical(INCREASE_SHIELD);
2633 // decrease shield recharge rate
2634 case DECREASE_SHIELD:
2635 hud_gauge_popup_start(HUD_ETS_GAUGE);
2636 return button_function_critical(DECREASE_SHIELD);
2639 // increase energy to engines
2640 case INCREASE_ENGINE:
2641 hud_gauge_popup_start(HUD_ETS_GAUGE);
2642 return button_function_critical(INCREASE_ENGINE);
2645 // decrease energy to engines
2646 case DECREASE_ENGINE:
2647 hud_gauge_popup_start(HUD_ETS_GAUGE);
2648 return button_function_critical(DECREASE_ENGINE);
2652 hud_gauge_popup_start(HUD_ETS_GAUGE);
2653 return button_function_critical(ETS_EQUALIZE);
2656 // equalize shield energy to all quadrants
2657 case SHIELD_EQUALIZE:
2658 return button_function_critical(SHIELD_EQUALIZE);
2661 // transfer shield energy to front
2662 case SHIELD_XFER_TOP:
2663 return button_function_critical(SHIELD_XFER_TOP);
2666 // transfer shield energy to rear
2667 case SHIELD_XFER_BOTTOM:
2668 return button_function_critical(SHIELD_XFER_BOTTOM);
2671 // transfer shield energy to left
2672 case SHIELD_XFER_LEFT:
2673 return button_function_critical(SHIELD_XFER_LEFT);
2676 // transfer shield energy to right
2677 case SHIELD_XFER_RIGHT:
2678 return button_function_critical(SHIELD_XFER_RIGHT);
2681 // transfer energy to shield from weapons
2683 return button_function_critical(XFER_SHIELD);
2686 // transfer energy to weapons from shield
2688 return button_function_critical(XFER_LASER);
2691 // message all netplayers button
2692 case MULTI_MESSAGE_ALL:
2693 multi_msg_key_down(MULTI_MSG_ALL);
2696 // message all friendlies button
2697 case MULTI_MESSAGE_FRIENDLY:
2698 multi_msg_key_down(MULTI_MSG_FRIENDLY);
2701 // message all hostiles button
2702 case MULTI_MESSAGE_HOSTILE:
2703 multi_msg_key_down(MULTI_MSG_HOSTILE);
2706 // message targeted ship (if player)
2707 case MULTI_MESSAGE_TARGET:
2708 multi_msg_key_down(MULTI_MSG_TARGET);
2711 // if i'm an observer, zoom to my targeted object
2712 case MULTI_OBSERVER_ZOOM_TO:
2713 multi_obs_zoom_to_target();
2716 // toggle between high and low HUD contrast
2717 case TOGGLE_HUD_CONTRAST:
2718 gamesnd_play_iface(SND_USER_SELECT);
2719 hud_toggle_contrast();
2722 // toggle network info
2723 case MULTI_TOGGLE_NETINFO:
2724 extern int Multi_display_netinfo;
2725 Multi_display_netinfo = !Multi_display_netinfo;
2728 // self destruct (multiplayer only)
2729 case MULTI_SELF_DESTRUCT:
2730 if(!(Game_mode & GM_MULTIPLAYER)){
2735 if((Net_player == NULL) || (Net_player->player == NULL)){
2739 // blow myself up, if I'm the server
2740 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
2741 if((Net_player->player->objnum >= 0) && (Net_player->player->objnum < MAX_OBJECTS) &&
2742 (Objects[Net_player->player->objnum].type == OBJ_SHIP) && (Objects[Net_player->player->objnum].instance >= 0) && (Objects[Net_player->player->objnum].instance < MAX_SHIPS)){
2744 ship_self_destruct(&Objects[Net_player->player->objnum]);
2747 // otherwise send a packet to the server
2749 send_self_destruct_packet();
2753 // following are not handled here, but we need to bypass the Int3()
2754 case LAUNCH_COUNTERMEASURE:
2756 case ONE_THIRD_THROTTLE:
2757 case TWO_THIRDS_THROTTLE:
2758 case MINUS_5_PERCENT_THROTTLE:
2759 case PLUS_5_PERCENT_THROTTLE:
2772 // Call functions for when buttons are pressed
2773 void button_info_do(button_info *bi)
2777 for (i=0; i<NUM_BUTTON_FIELDS; i++) {
2778 if ( bi->status[i] == 0 ){
2782 // at least one bit is set in the status integer
2783 for (j=0; j<32; j++) {
2785 // check if the bit is set. If button_function returns 1 (implying the action was taken), then unset the bit
2786 if ( bi->status[i] & (1 << j) ) {
2787 // always process buttons which are valid for demo playback
2788 if(button_function_demo_valid(32 * i + j)){
2789 bi->status[i] &= ~(1 << j);
2793 // if we're in demo playback, always clear the bits
2794 if(Game_mode & GM_DEMO_PLAYBACK){
2795 bi->status[i] &= ~(1 << j);
2797 // otherwise check as normal
2798 else if (button_function(32 * i + j)) {
2799 bi->status[i] &= ~(1 << j);
2808 // set the bit for the corresponding action n (BUTTON_ #define from KeyControl.h)
2809 void button_info_set(button_info *bi, int n)
2811 int field_num, bit_num;
2816 bi->status[field_num] |= (1 << bit_num);
2819 // unset the bit for the corresponding action n (BUTTON_ #define from KeyControl.h)
2820 void button_info_unset(button_info *bi, int n)
2822 int field_num, bit_num;
2827 bi->status[field_num] &= ~(1 << bit_num);
2830 int button_info_query(button_info *bi, int n)
2832 return bi->status[n / 32] & (1 << (n % 32));
2835 // clear out the button_info struct
2836 void button_info_clear(button_info *bi)
2840 for (i=0; i<NUM_BUTTON_FIELDS; i++) {
2845 // strip out all noncritical keys from the button info struct
2846 void button_strip_noncritical_keys(button_info *bi)
2850 // clear out all noncritical keys
2851 for(idx=0;idx<Non_critical_key_set_size;idx++){
2852 button_info_unset(bi,Non_critical_key_set[idx]);