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.2 2002/06/09 04:41:21 relnev
19 * added copyright header
21 * Revision 1.1.1.1 2002/05/03 03:28:09 root
25 * 47 9/09/99 11:40p Dave
26 * Handle an Assert() in beam code. Added supernova sounds. Play the right
27 * 2 end movies properly, based upon what the player did in the mission.
29 * 46 9/07/99 11:26p Andsager
30 * Fix "r" targeting key, making evaluate_ship_as_closest_target() and
31 * hud_target_live_turret() consider if turret is targeting player
33 * 45 9/03/99 1:31a Dave
34 * CD checking by act. Added support to play 2 cutscenes in a row
35 * seamlessly. Fixed super low level cfile bug related to files in the
36 * root directory of a CD. Added cheat code to set campaign mission # in
39 * 44 9/01/99 10:09a Dave
42 * 43 8/27/99 10:36a Dave
43 * Impose a 2% penalty for hitting the shield balance key.
45 * 42 8/27/99 9:57a Dave
46 * Enabled standard cheat codes. Allow player to continue in a campaing
47 * after using cheat codes.
49 * 41 8/26/99 9:45a Dave
50 * First pass at easter eggs and cheats.
52 * 40 8/24/99 1:49a Dave
53 * Fixed client-side afterburner stuttering. Added checkbox for no version
54 * checking on PXO join. Made button info passing more friendly between
57 * 39 8/22/99 5:53p Dave
58 * Scoring fixes. Added self destruct key. Put callsigns in the logfile
59 * instead of ship designations for multiplayer players.
61 * 38 8/19/99 10:59a Dave
62 * Packet loss detection.
64 * 37 8/18/99 12:09p Andsager
65 * Add debug if message has no anim for message. Make messages come from
68 * 36 8/05/99 2:05a Dave
71 * 35 8/01/99 12:39p Dave
72 * Added HUD contrast control key (for nebula).
74 * 34 7/31/99 2:30p Dave
75 * Added nifty mission message debug viewing keys.
77 * 33 7/21/99 8:10p Dave
78 * First run of supernova effect.
80 * 32 7/15/99 4:09p Andsager
81 * Disable cheats for FS2_DEMO
83 * 31 7/15/99 9:20a Andsager
84 * FS2_DEMO initial checkin
86 * 30 7/07/99 3:32p Dave
87 * Oops. Forgot to remove this.
89 * 29 7/02/99 4:31p Dave
90 * Much more sophisticated lightning support.
92 * 28 6/10/99 3:43p Dave
93 * Do a better job of syncing text colors to HUD gauges.
95 * 27 6/09/99 2:55p Andsager
96 * Allow multiple asteroid subtypes (of large, medium, small) and follow
99 * 26 5/24/99 5:45p Dave
100 * Added detail levels to the nebula, with a decent speedup. Split nebula
101 * lightning into its own section.
103 * 25 5/08/99 8:25p Dave
104 * Upped object pairs. First run of nebula lightning.
106 * 24 5/05/99 9:02p Dave
107 * Fixed D3D aabitmap rendering. Spiffed up nebula effect a bit (added
108 * rotations, tweaked values, made bitmap selection more random). Fixed
109 * D3D beam weapon clipping problem. Added D3d frame dumping.
111 * 23 5/03/99 9:07a Dave
112 * Pirate Bob. Changed beam test code a bit.
114 * 22 4/21/99 6:15p Dave
115 * Did some serious housecleaning in the beam code. Made it ready to go
116 * for anti-fighter "pulse" weapons. Fixed collision pair creation. Added
117 * a handy macro for recalculating collision pairs for a given object.
119 * 21 4/16/99 5:54p Dave
120 * Support for on/off style "stream" weapons. Real early support for
121 * target-painting lasers.
123 * 20 3/31/99 8:24p Dave
124 * Beefed up all kinds of stuff, incluging beam weapons, nebula effects
125 * and background nebulae. Added per-ship non-dimming pixel colors.
127 * 19 3/29/99 6:17p Dave
128 * More work on demo system. Got just about everything in except for
129 * blowing ships up, secondary weapons and player death/warpout.
131 * 18 3/28/99 5:58p Dave
132 * Added early demo code. Make objects move. Nice and framerate
133 * independant, but not much else. Don't use yet unless you're me :)
135 * 17 3/09/99 6:24p Dave
136 * More work on object update revamping. Identified several sources of
137 * unnecessary bandwidth.
139 * 16 2/21/99 6:01p Dave
140 * Fixed standalone WSS packets.
142 * 15 2/21/99 1:48p Dave
143 * Some code for monitoring datarate for multiplayer in detail.
145 * 14 1/21/99 2:06p Dave
146 * Final checkin for multiplayer testing.
148 * 13 1/19/99 3:57p Andsager
149 * Round 2 of variables
151 * 12 1/12/99 12:53a Dave
152 * More work on beam weapons - made collision detection very efficient -
153 * collide against all object types properly - made 3 movement types
154 * smooth. Put in test code to check for possible non-darkening pixels on
157 * 11 1/08/99 2:08p Dave
158 * Fixed software rendering for pofview. Super early support for AWACS and
161 * 10 12/06/98 2:36p Dave
162 * Drastically improved nebula fogging.
164 * 9 12/04/98 3:37p Andsager
165 * Added comment out asteroid launcher
167 * 8 11/19/98 4:19p Dave
168 * Put IPX sockets back in psnet. Consolidated all multiplayer config
171 * 7 11/05/98 5:55p Dave
172 * Big pass at reducing #includes
174 * 6 10/26/98 9:42a Dave
175 * Early flak gun support.
177 * 5 10/20/98 1:39p Andsager
178 * Make so sparks follow animated ship submodels. Modify
179 * ship_weapon_do_hit_stuff() and ship_apply_local_damage() to add
180 * submodel_num. Add submodel_num to multiplayer hit packet.
182 * 4 10/13/98 9:28a Dave
183 * Started neatening up freespace.h. Many variables renamed and
184 * reorganized. Added AlphaColors.[h,cpp]
186 * 3 10/09/98 2:57p Dave
187 * Starting splitting up OS stuff.
189 * 2 10/07/98 10:53a Dave
192 * 1 10/07/98 10:49a Dave
194 * 387 6/17/98 11:02a Lawrance
195 * show what cheat code is in the comment
197 * 386 6/09/98 5:15p Lawrance
198 * French/German localization
200 * 385 6/09/98 10:31a Hoffoss
201 * Created index numbers for all xstr() references. Any new xstr() stuff
202 * added from here on out should be added to the end if the list. The
203 * current list count can be found in FreeSpace.cpp (search for
206 * 384 6/01/98 11:43a John
207 * JAS & MK: Classified all strings for localization.
209 * 383 5/24/98 1:46p Mike
212 * 382 5/19/98 2:20p Mike
213 * Comment out nprintf().
215 * 381 5/19/98 12:19p Mike
218 * 380 5/19/98 11:11a Lawrance
219 * Make 'G' only target hostiles
221 * 379 5/18/98 11:00p Mike
222 * Adding support for cheat system.
224 * 378 5/18/98 12:41a Allender
225 * fixed subsystem problems on clients (i.e. not reporting properly on
226 * damage indicator). Fixed ingame join problem with respawns. minor
229 * 377 5/17/98 1:43a Dave
230 * Eradicated chatbox problems. Remove speed match for observers. Put in
231 * help screens for PXO. Fix messaging and end mission privelges. Fixed
232 * team select screen bugs. Misc UI fixes.
234 * 376 5/15/98 8:36p Lawrance
235 * Add 'target ship that last sent transmission' target key
237 * 375 5/14/98 11:07a Lawrance
238 * Ensure looped sounds get stopped before stopping all channels
240 * 374 5/12/98 11:59p Dave
241 * Put in some more functionality for Parallax Online.
243 * 373 5/11/98 5:29p Hoffoss
244 * Added mouse button mapped to joystick button support.
246 * 372 5/08/98 10:14a Lawrance
247 * Play sound when auto-targeting gets toggled.
249 * 371 5/04/98 9:25a Allender
250 * don't allow time compression in multiplayer
252 * 370 4/30/98 4:43p Allender
253 * trap player obj when changing dual fire status on ship
255 * 369 4/30/98 4:16p Peter
256 * fixes for critical button functions when a player (client) ship is dead
259 * 368 4/27/98 9:03a Dave
260 * Fixed a multiplayer sequencing bug where paused players who were in the
261 * options screen got an Assert when unpausing. Removed an optimiized
262 * build warning in keycontrol.
264 * 367 4/26/98 4:29p Lawrance
265 * Put back time compression keys... somehow they were trashed by a later
268 * 366 4/25/98 5:36p Mike
269 * Prevent player warpout if engine < 10%.
275 #include "linklist.h"
283 #include "contexthelp.h"
284 #include "gamesequence.h"
286 #include "missiongoals.h"
288 #include "hudtarget.h"
289 #include "optionsmenu.h"
290 #include "freespace.h"
291 #include "controlsconfig.h"
295 #include "multiutil.h"
300 #include "hudsquadmsg.h"
301 #include "eventmusic.h"
302 #include "animplay.h"
303 #include "freespace.h"
304 #include "cmeasure.h"
305 #include "missionhotkey.h"
306 #include "afterburner.h"
307 #include "missionparse.h"
308 #include "hudescort.h"
309 #include "hudshield.h"
310 #include "multiutil.h"
311 #include "multimsgs.h"
312 #include "keycontrol.h"
316 #include "hudobserver.h"
317 #include "missionlog.h"
318 #include "hudtargetbox.h"
320 #include "objcollide.h"
321 #include "hudconfig.h"
322 #include "missioncampaign.h"
324 #include "multi_respawn.h"
325 #include "multi_pmsg.h"
328 #include "multi_pause.h"
329 #include "multi_observer.h"
330 #include "multi_endgame.h"
332 #include "neblightning.h"
333 #include "supernova.h"
334 #include "missionmessage.h"
335 #include "mainhallmenu.h"
338 // --------------------------------------------------------------
340 // --------------------------------------------------------------
342 // --------------------------------------------------------------
344 // --------------------------------------------------------------
345 typedef struct asteroid_field {
346 vector min_bound; // Minimum range of field.
347 vector max_bound; // Maximum range of field.
348 vector vel; // Average asteroid moves at this velocity.
349 float speed; // Average speed of field
350 int num_initial_asteroids; // Number of asteroids at creation.
353 #define CHEAT_BUFFER_LEN 20
354 #define CHEATSPOT (CHEAT_BUFFER_LEN - 1)
356 char CheatBuffer[CHEAT_BUFFER_LEN+1];
359 char *Cheat_code_demo = NOX("33BE^(8]C01(:=BHt");
361 char *Cheat_code = NOX("33BE^(8]C01(:=BHt"); // www.freespace2.com
362 char *Cheat_code_fish = NOX("bDc9y+$;#AIDRoouM"); // vasudanswuvfishes
363 char *Cheat_code_headz = NOX("!;:::@>F7L?@@2:@A"); // humanheadsinside.
364 char *Cheat_code_tooled = NOX("sipp-^rM@L!U^usjX"); // tooledworkedowned
365 char *Cheat_code_pirate = NOX("MAP4YP[4=-2uC(yJ^"); // arrrrwalktheplank
366 char *Cheat_code_skip = NOX("7!ICkSI\"(8n3JesBP"); // skipmemymissionyo
368 // 666)6=N79+Z45=BE0e
369 int Tool_enabled = 0;
373 // list of the cheat codes
375 // "DavidPerry" NOX("0!XZQ*K.pu");
376 // NOX("&BvWJe=a?$VP*=@2W,2Y"); // Super-secret 20 character string!
377 //NOX("STs`nHqW\\lv#KD_aCSWN"); // solveditonceandforall (note double \\ as string contains \.
379 char *Cheat_code_in_game = NOX("///FES)P<A5=7CCB!n10"); // www.volition-inc.com
380 char *Cheat_code_movies = NOX("&BvWJe=a?$VP*=@2W,2Y"); // freespacestandsalone
381 char *Cheat_code_pirate = NOX("%,sPzoE>\\+_(Qs#+h-8o"); // arrwalktheplankmatey
386 int All_movies_enabled = 0;
388 //int Debug_allowed = 0;
392 extern int AI_watch_object;
393 extern int Countermeasures_enabled;
395 extern fix Game_time_compression;
397 extern float do_subobj_hit_stuff(object *ship_obj, object *other_obj, vector *hitpos, float damage);
399 extern void mission_goal_mark_all_true( int type );
401 int Normal_key_set[] = {
404 TARGET_NEXT_CLOSEST_HOSTILE,
405 TARGET_PREV_CLOSEST_HOSTILE,
406 TARGET_NEXT_CLOSEST_FRIENDLY,
407 TARGET_PREV_CLOSEST_FRIENDLY,
408 TARGET_TARGETS_TARGET,
409 TARGET_SHIP_IN_RETICLE,
410 TARGET_LAST_TRANMISSION_SENDER,
411 TARGET_CLOSEST_SHIP_ATTACKING_TARGET,
412 TARGET_CLOSEST_SHIP_ATTACKING_SELF,
414 TOGGLE_AUTO_TARGETING,
415 TARGET_SUBOBJECT_IN_RETICLE,
416 TARGET_PREV_SUBOBJECT,
417 TARGET_NEXT_SUBOBJECT,
418 STOP_TARGETING_SUBSYSTEM,
420 TARGET_NEXT_UNINSPECTED_CARGO,
421 TARGET_PREV_UNINSPECTED_CARGO,
423 TARGET_NEXT_LIVE_TURRET,
424 TARGET_PREV_LIVE_TURRET,
431 ATTACK_SUBSYSTEM_MESSAGE,
450 TARGET_NEXT_ESCORT_SHIP,
474 TOGGLE_AUTO_MATCH_TARGET_SPEED,
477 VIEW_EXTERNAL_TOGGLE_CAMERA_LOCK,
478 LAUNCH_COUNTERMEASURE,
481 PLUS_5_PERCENT_THROTTLE,
482 MINUS_5_PERCENT_THROTTLE,
486 TARGET_CLOSEST_REPAIR_SHIP,
489 MULTI_MESSAGE_FRIENDLY,
490 MULTI_MESSAGE_HOSTILE,
491 MULTI_MESSAGE_TARGET,
492 MULTI_OBSERVER_ZOOM_TO,
499 MULTI_TOGGLE_NETINFO,
503 int Dead_key_set[] = {
506 TARGET_NEXT_CLOSEST_HOSTILE,
507 TARGET_PREV_CLOSEST_HOSTILE,
508 TARGET_NEXT_CLOSEST_FRIENDLY,
509 TARGET_PREV_CLOSEST_FRIENDLY,
510 TARGET_TARGETS_TARGET,
511 TARGET_CLOSEST_SHIP_ATTACKING_TARGET,
513 TOGGLE_AUTO_TARGETING,
514 TARGET_SUBOBJECT_IN_RETICLE,
515 TARGET_PREV_SUBOBJECT,
516 TARGET_NEXT_SUBOBJECT,
517 STOP_TARGETING_SUBSYSTEM,
519 TARGET_NEXT_LIVE_TURRET,
520 TARGET_PREV_LIVE_TURRET,
531 TARGET_NEXT_ESCORT_SHIP,
532 TARGET_CLOSEST_REPAIR_SHIP,
535 MULTI_MESSAGE_FRIENDLY,
536 MULTI_MESSAGE_HOSTILE,
537 MULTI_MESSAGE_TARGET,
538 MULTI_OBSERVER_ZOOM_TO,
544 int Critical_key_set[] = {
563 int Non_critical_key_set[] = {
567 TOGGLE_AUTO_MATCH_TARGET_SPEED,
570 TARGET_NEXT_CLOSEST_HOSTILE,
571 TARGET_PREV_CLOSEST_HOSTILE,
572 TOGGLE_AUTO_TARGETING,
573 TARGET_NEXT_CLOSEST_FRIENDLY,
574 TARGET_PREV_CLOSEST_FRIENDLY,
575 TARGET_SHIP_IN_RETICLE,
576 TARGET_LAST_TRANMISSION_SENDER,
577 TARGET_CLOSEST_REPAIR_SHIP,
578 TARGET_CLOSEST_SHIP_ATTACKING_TARGET,
580 TARGET_CLOSEST_SHIP_ATTACKING_SELF,
581 TARGET_TARGETS_TARGET,
582 TARGET_SUBOBJECT_IN_RETICLE,
583 TARGET_PREV_SUBOBJECT,
584 TARGET_NEXT_SUBOBJECT,
585 STOP_TARGETING_SUBSYSTEM,
588 TARGET_NEXT_UNINSPECTED_CARGO,
589 TARGET_PREV_UNINSPECTED_CARGO,
591 TARGET_NEXT_LIVE_TURRET,
592 TARGET_PREV_LIVE_TURRET,
596 ATTACK_SUBSYSTEM_MESSAGE,
607 VIEW_EXTERNAL_TOGGLE_CAMERA_LOCK,
615 TARGET_NEXT_ESCORT_SHIP,
617 MULTI_MESSAGE_FRIENDLY,
618 MULTI_MESSAGE_HOSTILE,
619 MULTI_MESSAGE_TARGET,
620 MULTI_OBSERVER_ZOOM_TO,
623 MULTI_TOGGLE_NETINFO,
628 // set sizes of the key sets automatically
629 int Normal_key_set_size = sizeof(Normal_key_set) / sizeof(int);
630 int Dead_key_set_size = sizeof(Dead_key_set) / sizeof(int);
631 int Critical_key_set_size = sizeof(Critical_key_set) / sizeof(int);
632 int Non_critical_key_set_size = sizeof(Non_critical_key_set) / sizeof(int);
634 // --------------------------------------------------------------
635 // routine to process keys used only for debugging
636 // --------------------------------------------------------------
639 void debug_cycle_player_ship(int delta)
641 if ( Player_obj == NULL )
644 int si_index = Ships[Player_obj->instance].ship_info_index;
649 if ( si_index > MAX_SHIP_TYPES ){
653 si_index = MAX_SHIP_TYPES - 1;
655 sip = &Ship_info[si_index];
656 if ( sip->flags & SIF_PLAYER_SHIP ){
662 if ( sanity > MAX_SHIP_TYPES ){
667 change_ship_type(Player_obj->instance, si_index);
668 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Player ship changed to %s", 0), Ship_info[si_index].name);
671 // cycle targeted ship to next ship in that species
672 void debug_cycle_targeted_ship(int delta)
676 int si_index, species;
677 char name[NAME_LENGTH];
679 if ( Player_ai->target_objnum == -1 )
682 objp = &Objects[Player_ai->target_objnum];
683 if ( objp->type != OBJ_SHIP )
686 si_index = Ships[objp->instance].ship_info_index;
687 Assert(si_index != -1 );
688 species = Ship_info[si_index].species;
694 if ( si_index > MAX_SHIP_TYPES )
697 si_index = MAX_SHIP_TYPES-1;
700 sip = &Ship_info[si_index];
702 // if it has test in the name, jump over it
703 strcpy(name, sip->name);
705 if ( strstr(name,NOX("test")) != NULL )
708 if ( sip->species == species && (sip->flags & (SIF_FIGHTER | SIF_BOMBER | SIF_TRANSPORT) ) )
713 if ( sanity > MAX_SHIP_TYPES )
717 change_ship_type(objp->instance, si_index);
718 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Changed player target to %s", 1), Ship_info[si_index].name);
721 void debug_max_secondary_weapons(object *objp)
724 ship *shipp = &Ships[objp->instance];
725 ship_info *sip = &Ship_info[shipp->ship_info_index];
727 for ( index = 0; index < MAX_SECONDARY_BANKS; index++ ) {
728 shipp->weapons.secondary_bank_ammo[index] = sip->secondary_bank_ammo_capacity[index];
732 void debug_change_song(int delta)
735 if ( event_music_next_soundtrack(delta) != -1 ) {
736 event_music_get_soundtrack_name(buf);
737 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Soundtrack changed to: %s", 2), buf);
740 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Event music is not playing", 3));
744 //extern void set_global_ignore_object(int objnum);
746 extern void hud_target_asteroid();
747 extern int Framerate_delay;
749 extern void snd_stop_any_sound();
751 void process_debug_keys(int k)
754 if ( !Debug_allowed )
758 // if ( (k & KEY_DEBUGGED) && (Game_mode & GM_RECORDING_DEMO) )
762 case KEY_DEBUGGED + KEY_H:
763 hud_target_toggle_hidden_from_sensors();
766 case KEY_DEBUGGED + KEY_F:
769 for (i=0; i<NUM_HUD_GAUGES; i++) {
770 hud_gauge_start_flash(i);
773 extern int wacky_scheme;
774 if(wacky_scheme == 3){
781 case KEY_DEBUGGED + KEY_ALTED + KEY_F:
782 Framerate_delay += 10;
783 HUD_printf(XSTR( "Framerate delay increased to %i milliseconds per frame.", 4), Framerate_delay);
786 case KEY_DEBUGGED + KEY_ALTED + KEY_SHIFTED + KEY_F:
787 Framerate_delay -= 10;
788 if (Framerate_delay < 0)
791 HUD_printf(XSTR( "Framerate delay decreased to %i milliseconds per frame.", 5), Framerate_delay);
794 case KEY_DEBUGGED + KEY_C:
795 case KEY_DEBUGGED1 + KEY_C:
796 // hud_enemymsg_toggle();
797 if(Player_obj->flags & OF_COLLIDES){
798 obj_set_flags(Player_obj, Player_obj->flags & ~(OF_COLLIDES));
799 HUD_sourced_printf(HUD_SOURCE_HIDDEN, "Player no longer collides");
801 obj_set_flags(Player_obj, Player_obj->flags | OF_COLLIDES);
802 HUD_sourced_printf(HUD_SOURCE_HIDDEN, "Player collides");
806 case KEY_DEBUGGED + KEY_SHIFTED + KEY_C:
807 case KEY_DEBUGGED1 + KEY_SHIFTED + KEY_C:
808 Countermeasures_enabled = !Countermeasures_enabled;
809 HUD_printf(XSTR( "Countermeasure firing: %s", 6), Countermeasures_enabled ? XSTR( "ENABLED", 7) : XSTR( "DISABLED", 8));
812 case KEY_DEBUGGED + KEY_E:
813 gameseq_post_event(GS_EVENT_EVENT_DEBUG);
816 case KEY_DEBUGGED + KEY_COMMA:
817 if ( Game_time_compression > (F1_0/4) ){ // can't compress below 0.25
818 Game_time_compression /= 2;
821 case KEY_DEBUGGED + KEY_PERIOD:
822 if ( Game_time_compression < (F1_0*8) ){
823 Game_time_compression *= 2;
827 // Kill! the currently targeted ship.
828 case KEY_DEBUGGED + KEY_K:
829 case KEY_DEBUGGED1 + KEY_K:
830 if (Player_ai->target_objnum != -1) {
831 object *objp = &Objects[Player_ai->target_objnum];
833 switch (objp->type) {
835 ship_apply_local_damage( objp, Player_obj, &objp->pos, 100000.0f, MISS_SHIELDS, CREATE_SPARKS);
836 ship_apply_local_damage( objp, Player_obj, &objp->pos, 1.0f, MISS_SHIELDS, CREATE_SPARKS);
839 Weapons[objp->instance].lifeleft = 0.01f;
846 // play the next mission message
847 case KEY_DEBUGGED + KEY_V:
848 extern int Message_debug_index;
849 extern int Num_messages_playing;
850 // stop any other messages
851 if(Num_messages_playing){
856 if(Message_debug_index >= Num_messages - 1){
857 Message_debug_index = Num_builtin_messages;
859 Message_debug_index++;
863 message_send_unique_to_player( Messages[Message_debug_index].name, Message_waves[Messages[Message_debug_index].wave_info.index].name, MESSAGE_SOURCE_SPECIAL, MESSAGE_PRIORITY_HIGH, 0, 0 );
864 if (Messages[Message_debug_index].avi_info.index == -1) {
865 HUD_printf("No anim set for message \"%s\"; None will play!", Messages[Message_debug_index].name);
869 // play the previous mission message
870 case KEY_DEBUGGED + KEY_SHIFTED + KEY_V:
871 extern int Message_debug_index;
872 extern int Num_messages_playing;
873 // stop any other messages
874 if(Num_messages_playing){
878 // go maybe go down one
879 if(Message_debug_index == Num_builtin_messages - 1){
880 Message_debug_index = Num_builtin_messages;
881 } else if(Message_debug_index > Num_builtin_messages){
882 Message_debug_index--;
886 message_send_unique_to_player( Messages[Message_debug_index].name, Message_waves[Messages[Message_debug_index].wave_info.index].name, MESSAGE_SOURCE_SPECIAL, MESSAGE_PRIORITY_HIGH, 0, 0 );
887 if (Messages[Message_debug_index].avi_info.index == -1) {
888 HUD_printf("No avi associated with this message; None will play!");
892 // reset to the beginning of mission messages
893 case KEY_DEBUGGED + KEY_ALTED + KEY_V:
894 extern int Message_debug_index;
895 Message_debug_index = Num_builtin_messages - 1;
896 HUD_printf("Resetting to first mission message");
899 // Kill! the currently targeted ship.
900 case KEY_DEBUGGED + KEY_ALTED + KEY_SHIFTED + KEY_K:
901 case KEY_DEBUGGED1 + KEY_ALTED + KEY_SHIFTED + KEY_K:
902 if (Player_ai->target_objnum != -1) {
903 object *objp = &Objects[Player_ai->target_objnum];
905 if (objp->type == OBJ_SHIP) {
906 ship_apply_local_damage( objp, Player_obj, &objp->pos, Ship_info[Ships[objp->instance].ship_info_index].initial_hull_strength * 0.1f + 10.0f, MISS_SHIELDS, CREATE_SPARKS);
911 // Kill the currently targeted subsystem.
912 case KEY_DEBUGGED + KEY_SHIFTED + KEY_K:
913 case KEY_DEBUGGED1 + KEY_SHIFTED + KEY_K:
914 if ((Player_ai->target_objnum != -1) && (Player_ai->targeted_subsys != NULL)) {
915 object *objp = &Objects[Player_ai->target_objnum];
916 if ( objp->type == OBJ_SHIP ) {
917 ship *sp = &Ships[objp->instance];
920 get_subsystem_world_pos(objp, Player_ai->targeted_subsys, &g_subobj_pos);
922 do_subobj_hit_stuff(objp, Player_obj, &g_subobj_pos, (float) -Player_ai->targeted_subsys->system_info->type); //100.0f);
924 if ( sp->subsys_info[SUBSYSTEM_ENGINE].current_hits <= 0.0f ) {
925 mission_log_add_entry(LOG_SHIP_DISABLED, sp->ship_name, NULL );
926 sp->flags |= SF_DISABLED; // add the disabled flag
929 if ( sp->subsys_info[SUBSYSTEM_TURRET].current_hits <= 0.0f ) {
930 mission_log_add_entry(LOG_SHIP_DISARMED, sp->ship_name, NULL );
931 // sp->flags |= SF_DISARMED; // add the disarmed flag
937 case KEY_DEBUGGED + KEY_ALTED + KEY_K:
938 case KEY_DEBUGGED1 + KEY_ALTED + KEY_K:
940 float shield, integrity;
943 vm_vec_rand_vec_quick(&randvec);
944 vm_vec_scale_add(&pos, &Player_obj->pos, &randvec, Player_obj->radius);
945 ship_apply_local_damage(Player_obj, Player_obj, &pos, 25.0f, MISS_SHIELDS, CREATE_SPARKS);
946 hud_get_target_strength(Player_obj, &shield, &integrity);
947 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "You knocked yourself down to %7.3f percent hull.\n", 9), 100.0f * integrity);
951 // Whack down the player's shield and hull by a little more than 50%
952 // Select next object to be viewed by AI.
953 case KEY_DEBUGGED + KEY_I:
954 case KEY_DEBUGGED1 + KEY_I:
955 Player_obj->flags ^= OF_INVULNERABLE;
956 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "You are %s", 10), Player_obj->flags & OF_INVULNERABLE ? XSTR( "now INVULNERABLE!", 11) : XSTR( "no longer invulnerable...", 12));
959 case KEY_DEBUGGED + KEY_SHIFTED + KEY_I:
960 case KEY_DEBUGGED1 + KEY_SHIFTED + KEY_I:
961 if (Player_ai->target_objnum != -1) {
962 object *objp = &Objects[Player_ai->target_objnum];
964 objp->flags ^= OF_INVULNERABLE;
965 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Player's target [%s] is %s", 13), Ships[objp->instance].ship_name, objp->flags & OF_INVULNERABLE ? XSTR( "now INVULNERABLE!", 11) : XSTR( "no longer invulnerable...", 12));
969 case KEY_DEBUGGED + KEY_ALTED + KEY_I:
970 if (Player_ai->target_objnum != -1)
971 set_global_ignore_object(Player_ai->target_objnum);
975 case KEY_DEBUGGED + KEY_N:
977 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Spewing debug info about object #%d", 14), AI_watch_object);
980 case KEY_DEBUGGED + KEY_O:
981 // case KEY_DEBUGGED1 + KEY_O:
982 toggle_player_object();
985 case KEY_DEBUGGED + KEY_SHIFTED + KEY_O:
986 extern int Debug_octant;
987 if(Debug_octant == 7){
992 nprintf(("General", "Debug_octant == %d\n", Debug_octant));
995 case KEY_DEBUGGED + KEY_P:
999 case KEY_DEBUGGED + KEY_W:
1000 case KEY_DEBUGGED1 + KEY_W:
1001 case KEY_DEBUGGED + KEY_SHIFTED + KEY_W:
1002 case KEY_DEBUGGED1 + KEY_SHIFTED + KEY_W:
1003 // temp code for testing purposes, toggles weapon energy cheat
1004 Weapon_energy_cheat = !Weapon_energy_cheat;
1005 if (Weapon_energy_cheat) {
1006 if (k & KEY_SHIFTED)
1007 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Weapon energy and missile count will always be at full ALL SHIPS!", 15));
1009 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Weapon energy and missile count will always be at full for player", 16));
1011 debug_max_secondary_weapons(Player_obj);
1012 if (k & KEY_SHIFTED) {
1015 for ( objp = GET_FIRST(&obj_used_list); objp !=END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp) )
1016 if (objp->type == OBJ_SHIP)
1017 debug_max_secondary_weapons(objp);
1021 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Normal weapon energy system / missile count restored", 17));
1025 case KEY_DEBUGGED + KEY_G:
1026 // case KEY_DEBUGGED1 + KEY_G:
1027 mission_goal_mark_all_true( PRIMARY_GOAL );
1030 case KEY_DEBUGGED + KEY_G + KEY_SHIFTED:
1031 // case KEY_DEBUGGED1 + KEY_G + KEY_SHIFTED:
1032 mission_goal_mark_all_true( SECONDARY_GOAL );
1035 case KEY_DEBUGGED + KEY_G + KEY_ALTED:
1036 // case KEY_DEBUGGED1 + KEY_G + KEY_ALTED:
1037 mission_goal_mark_all_true( BONUS_GOAL );
1040 case KEY_DEBUGGED + KEY_9: {
1041 case KEY_DEBUGGED1 + KEY_9:
1044 shipp = &Ships[Player_obj->instance];
1045 shipp->weapons.secondary_bank_weapons[shipp->weapons.current_secondary_bank]++;
1046 if ( shipp->weapons.secondary_bank_weapons[shipp->weapons.current_secondary_bank] >= Num_weapon_types )
1047 shipp->weapons.secondary_bank_weapons[shipp->weapons.current_secondary_bank] = First_secondary_index;
1049 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Secondary Weapon forced to %s", 18), Weapon_info[shipp->weapons.secondary_bank_weapons[shipp->weapons.current_secondary_bank]].name);
1054 case KEY_DEBUGGED + KEY_SHIFTED + KEY_9: {
1055 case KEY_DEBUGGED1 + KEY_SHIFTED + KEY_9:
1058 shipp = &Ships[Player_obj->instance];
1059 shipp->weapons.secondary_bank_weapons[shipp->weapons.current_secondary_bank]--;
1060 if ( shipp->weapons.secondary_bank_weapons[shipp->weapons.current_secondary_bank] < 0)
1061 shipp->weapons.secondary_bank_weapons[shipp->weapons.current_secondary_bank] = Num_weapon_types - 1;
1063 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Secondary Weapon forced to %s", 18), Weapon_info[shipp->weapons.secondary_bank_weapons[shipp->weapons.current_secondary_bank]].name);
1069 case KEY_DEBUGGED + KEY_U: {
1070 case KEY_DEBUGGED1 + KEY_U:
1072 extern asteroid_field Asteroid_field;
1073 object *asteroid_create(asteroid_field *asfieldp, int asteroid_type, int subtype);
1074 object *objp = asteroid_create(&Asteroid_field, 0, 0);
1076 vm_vec_copy_scale(&vel, &Player_obj->orient.fvec, 50.0f);
1077 objp->phys_info.vel = vel;
1078 objp->phys_info.desired_vel = vel;
1079 objp->pos = Player_obj->pos;
1080 //mission_goal_mark_all_true( PRIMARY_GOAL );
1085 case KEY_DEBUGGED + KEY_0: {
1086 case KEY_DEBUGGED1 + KEY_0:
1089 shipp = &Ships[Player_obj->instance];
1090 shipp->weapons.primary_bank_weapons[shipp->weapons.current_primary_bank]++;
1091 if ( shipp->weapons.primary_bank_weapons[shipp->weapons.current_primary_bank] >= First_secondary_index )
1092 shipp->weapons.primary_bank_weapons[shipp->weapons.current_primary_bank] = 0;
1094 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Primary Weapon forced to %s", 19), Weapon_info[shipp->weapons.primary_bank_weapons[shipp->weapons.current_primary_bank]].name);
1098 case KEY_DEBUGGED + KEY_SHIFTED + KEY_0: {
1099 case KEY_DEBUGGED1 + KEY_SHIFTED + KEY_0:
1102 shipp = &Ships[Player_obj->instance];
1103 shipp->weapons.primary_bank_weapons[shipp->weapons.current_primary_bank]--;
1104 if ( shipp->weapons.primary_bank_weapons[shipp->weapons.current_primary_bank] < 0)
1105 shipp->weapons.primary_bank_weapons[shipp->weapons.current_primary_bank] = First_secondary_index-1 ;
1107 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Primary Weapon forced to %s", 19), Weapon_info[shipp->weapons.primary_bank_weapons[shipp->weapons.current_primary_bank]].name);
1111 case KEY_DEBUGGED + KEY_J: {
1112 int new_pattern = event_music_return_current_pattern();
1115 if ( new_pattern >= MAX_PATTERNS )
1118 event_music_change_pattern(new_pattern);
1122 case KEY_DEBUGGED + KEY_M: {
1123 if ( Event_music_enabled ) {
1124 event_music_disable();
1125 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Event music disabled", 20));
1128 event_music_enable();
1129 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Event music enabled", 21));
1135 case KEY_DEBUGGED + KEY_R: {
1136 // case KEY_DEBUGGED1 + KEY_R:
1137 if (Player_ai->target_objnum != -1)
1138 ai_issue_rearm_request(&Objects[Player_ai->target_objnum]);
1140 ai_issue_rearm_request(Player_obj);
1145 case KEY_DEBUGGED + KEY_SHIFTED + KEY_UP:
1146 Game_detail_level++;
1147 HUD_printf( XSTR( "Detail level set to %+d\n", 22), Game_detail_level );
1150 case KEY_DEBUGGED + KEY_SHIFTED + KEY_DOWN:
1151 Game_detail_level--;
1152 HUD_printf( XSTR( "Detail level set to %+d\n", 22), Game_detail_level );
1156 case KEY_DEBUGGED + KEY_SHIFTED + KEY_T: {
1157 extern int Test_begin;
1159 if ( Test_begin == 1 )
1163 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Frame Rate test started", 23));
1168 case KEY_DEBUGGED + KEY_D:
1169 extern int OO_update_index;
1171 if(MULTIPLAYER_MASTER){
1174 } while((OO_update_index < (MAX_PLAYERS-1)) && !MULTI_CONNECTED(Net_players[OO_update_index]));
1175 if(OO_update_index >= MAX_PLAYERS-1){
1176 OO_update_index = -1;
1179 if(OO_update_index < 0){
1180 OO_update_index = MY_NET_PLAYER_NUM;
1182 OO_update_index = -1;
1187 // change player ship to next flyable type
1188 case KEY_DEBUGGED + KEY_RIGHT:
1189 debug_cycle_player_ship(1);
1192 // change player ship to previous flyable ship
1193 case KEY_DEBUGGED + KEY_LEFT:
1194 debug_cycle_player_ship(-1);
1197 // cycle target to ship
1198 case KEY_DEBUGGED + KEY_SHIFTED + KEY_RIGHT:
1199 debug_cycle_targeted_ship(1);
1202 // cycle target to previous ship
1203 case KEY_DEBUGGED + KEY_SHIFTED + KEY_LEFT:
1204 debug_cycle_targeted_ship(-1);
1207 // change species of the targeted ship
1208 case KEY_DEBUGGED + KEY_S: {
1209 if ( Player_ai->target_objnum < 0 )
1215 objp = &Objects[Player_ai->target_objnum];
1216 if ( objp->type != OBJ_SHIP )
1219 sip = &Ship_info[Ships[objp->instance].ship_info_index];
1221 if ( sip->species > SPECIES_SHIVAN )
1224 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Species of target changed to: %s", 24), Species_names[sip->species]);
1228 case KEY_DEBUGGED + KEY_SHIFTED + KEY_S:
1229 game_increase_skill_level();
1230 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Skill level set to %s.", 25), Skill_level_names(Game_skill_level));
1233 // kill all missiles
1234 case KEY_DEBUGGED + KEY_SHIFTED + KEY_1:
1237 case KEY_DEBUGGED + KEY_SHIFTED + KEY_2:
1240 case KEY_DEBUGGED + KEY_SHIFTED + KEY_3:
1243 case KEY_DEBUGGED + KEY_SHIFTED + KEY_4:
1246 case KEY_DEBUGGED + KEY_SHIFTED + KEY_5:
1249 case KEY_DEBUGGED + KEY_SHIFTED + KEY_6:
1252 case KEY_DEBUGGED + KEY_SHIFTED + KEY_7:
1255 case KEY_DEBUGGED + KEY_SHIFTED + KEY_8:
1258 case KEY_DEBUGGED + KEY_SHIFTED + KEY_9:
1262 case KEY_DEBUGGED + KEY_CTRLED + KEY_1:
1265 case KEY_DEBUGGED + KEY_CTRLED + KEY_2:
1268 case KEY_DEBUGGED + KEY_CTRLED + KEY_3:
1272 case KEY_DEBUGGED + KEY_T: {
1274 event_music_get_info(buf);
1275 HUD_sourced_printf(HUD_SOURCE_HIDDEN, buf);
1279 case KEY_DEBUGGED + KEY_UP:
1280 debug_change_song(1);
1283 case KEY_DEBUGGED + KEY_DOWN:
1284 debug_change_song(-1);
1287 case KEY_PADMINUS: {
1290 if ( keyd_pressed[KEY_1] ) {
1295 if ( keyd_pressed[KEY_2] ) {
1297 HUD_color_green -= 4;
1300 if ( keyd_pressed[KEY_3] ) {
1302 HUD_color_blue -= 4;
1311 case KEY_DEBUGGED + KEY_Y:
1313 // blast a debug lightning bolt in front of the player
1314 vector start, strike;
1316 vm_vec_scale_add(&start, &Player_obj->pos, &Player_obj->orient.fvec, 300.0f);
1317 vm_vec_scale_add2(&start, &Player_obj->orient.rvec, -300.0f);
1318 vm_vec_scale_add(&strike, &start, &Player_obj->orient.rvec, 600.0f);
1319 nebl_bolt(DEBUG_BOLT, &start, &strike);
1328 if ( keyd_pressed[KEY_1] ) {
1333 if ( keyd_pressed[KEY_2] ) {
1335 HUD_color_green += 4;
1338 if ( keyd_pressed[KEY_3] ) {
1340 HUD_color_blue += 4;
1353 void ppsk_hotkeys(int k)
1358 // use k to check for keys that can have Shift,Ctrl,Alt,Del status
1362 k &= ~KEY_DEBUGGED; // since hitting F11 will set this bit
1374 hotkey_set = mission_hotkey_get_set_num(k);
1375 if ( !(Players[Player_num].flags & PLAYER_FLAGS_MSG_MODE) )
1376 hud_target_hotkey_select( hotkey_set );
1378 hud_squadmsg_hotkey_select( hotkey_set );
1382 case KEY_F5 + KEY_SHIFTED:
1383 case KEY_F6 + KEY_SHIFTED:
1384 case KEY_F7 + KEY_SHIFTED:
1385 case KEY_F8 + KEY_SHIFTED:
1386 case KEY_F9 + KEY_SHIFTED:
1387 case KEY_F10 + KEY_SHIFTED:
1388 case KEY_F11 + KEY_SHIFTED:
1389 case KEY_F12 + KEY_SHIFTED:
1390 hotkey_set = mission_hotkey_get_set_num(k&(~KEY_SHIFTED));
1391 mprintf(("Adding to set %d\n", hotkey_set+1));
1392 if ( Player_ai->target_objnum == -1)
1393 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "No target to add/remove from set %d.", 26), hotkey_set+1);
1395 hud_target_hotkey_add_remove( hotkey_set, &Objects[Player_ai->target_objnum], HOTKEY_USER_ADDED);
1396 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "%s added to set %d. (F%d)", 27), Ships[Objects[Player_ai->target_objnum].instance].ship_name, hotkey_set, 4+hotkey_set+1);
1401 case KEY_F5 + KEY_SHIFTED + KEY_ALTED:
1402 case KEY_F6 + KEY_SHIFTED + KEY_ALTED:
1403 case KEY_F7 + KEY_SHIFTED + KEY_ALTED:
1404 case KEY_F8 + KEY_SHIFTED + KEY_ALTED:
1405 case KEY_F9 + KEY_SHIFTED + KEY_ALTED:
1406 case KEY_F10 + KEY_SHIFTED + KEY_ALTED:
1407 case KEY_F11 + KEY_SHIFTED + KEY_ALTED:
1408 case KEY_F12 + KEY_SHIFTED + KEY_ALTED:
1409 hotkey_set = mission_hotkey_get_set_num(k & ~KEY_SHIFTED+KEY_ALTED);
1410 hud_target_hotkey_clear( hotkey_set );
1413 case KEY_SHIFTED + KEY_MINUS:
1414 if ( HUD_color_alpha > HUD_COLOR_ALPHA_USER_MIN ) {
1419 /* case KEY_SHIFTED + KEY_U:
1421 object *debris_create(object *source_obj, int model_num, int submodel_num, vector *pos, vector *exp_center, int hull_flag, float exp_force);
1423 object *temp = debris_create(Player_obj, Ships[0].modelnum, model_get(Ships[0].modelnum)->debris_objects[0], &Player_obj->pos, &Player_obj->pos, 1, 1.0f);
1425 temp->hull_strength = 5000.0f;
1426 int objnum = temp - Objects;
1427 vm_vec_copy_scale(&Objects[objnum].phys_info.vel, &Player_obj->orient.fvec, 30.0f);
1433 case KEY_SHIFTED + KEY_EQUAL:
1434 if ( HUD_color_alpha < HUD_COLOR_ALPHA_USER_MAX ) {
1445 // check keypress 'key' against a set of valid controls and mark the match in the
1446 // player's button info bitfield. Also checks joystick controls in the set.
1448 // key = scancode (plus modifiers).
1449 // count = total size of the list
1450 // list = list of Control_config struct action indices to check for
1451 void process_set_of_keys(int key, int count, int *list)
1455 for (i=0; i<count; i++)
1456 if (check_control(list[i], key))
1457 button_info_set(&Player->bi, list[i]);
1460 // routine to process keys used for player ship stuff (*not* ship movement).
1461 void process_player_ship_keys(int k)
1465 masked_k = k & ~KEY_CTRLED; // take out CTRL modifier only
1467 // moved this line to beginning of function since hotkeys now encompass
1468 // F5 - F12. We can return after using F11 as a hotkey.
1469 ppsk_hotkeys(masked_k);
1470 if (keyd_pressed[KEY_DEBUG_KEY]){
1474 // if we're in supernova mode. do nothing
1475 if(Player->control_mode == PCM_SUPERNOVA){
1479 // pass the key to the squadmate messaging code. If the messaging code took the key, then return
1480 // from here immediately since we don't want to do further key processing.
1481 if ( hud_squadmsg_read_key(k) )
1484 if ( Player->control_mode == PCM_NORMAL ) {
1485 // The following things are not legal to do while dead.
1486 if ( !(Game_mode & GM_DEAD) ) {
1487 process_set_of_keys(masked_k, Normal_key_set_size, Normal_key_set);
1489 process_set_of_keys(masked_k, Dead_key_set_size, Dead_key_set);
1496 // Handler for when player hits 'ESC' during the game
1497 void game_do_end_mission_popup()
1499 int pf_flags, choice;
1500 // char savegame_filename[_MAX_FNAME];
1502 // do the multiplayer version of this
1503 if(Game_mode & GM_MULTIPLAYER){
1504 multi_quit_game(PROMPT_ALL);
1507 // single player version....
1508 // do housekeeping things.
1510 game_stop_looped_sounds();
1513 pf_flags = PF_BODY_BIG | PF_USE_AFFIRMATIVE_ICON | PF_USE_NEGATIVE_ICON;
1514 choice = popup(pf_flags, 3, POPUP_NO, XSTR( "&Yes, Quit", 28), XSTR( "Yes, &Restart", 29), XSTR( "Do you really want to end the mission?", 30));
1518 // save the game before quitting if in campaign mode
1519 // MWA -- 3/26/98 -- no more save/restore!!!!
1521 if ( Game_mode & GM_CAMPAIGN_MODE ) {
1522 memset(savegame_filename, 0, _MAX_FNAME);
1523 mission_campaign_savefile_generate_root(savegame_filename);
1524 strcat(savegame_filename, NOX("svg"));
1525 if ( state_save_all(savegame_filename) ) {
1526 Int3(); // could not save this game
1530 gameseq_post_event(GS_EVENT_END_GAME);
1534 gameseq_post_event(GS_EVENT_ENTER_GAME);
1538 break; // do nothing
1546 // handle pause keypress
1547 void game_process_pause_key()
1549 // special processing for multiplayer
1550 if (Game_mode & GM_MULTIPLAYER) {
1551 if(Multi_pause_status){
1552 multi_pause_request(0);
1554 multi_pause_request(1);
1557 gameseq_post_event( GS_EVENT_PAUSE_GAME );
1561 #define WITHIN_BBOX() do { \
1562 float scale = 2.0f; \
1563 polymodel *pm = model_get(s_check->modelnum); \
1566 vector temp = new_obj->pos; \
1568 vm_vec_sub2(&temp, &hit_check->pos); \
1569 vm_vec_rotate(&gpos, &temp, &hit_check->orient); \
1570 if((gpos.x >= pm->mins.x * scale) && (gpos.y >= pm->mins.y * scale) && (gpos.z >= pm->mins.z * scale) && (gpos.x <= pm->maxs.x * scale) && (gpos.y <= pm->maxs.y * scale) && (gpos.z <= pm->maxs.z * scale)) { \
1576 #define MOVE_AWAY_BBOX() do { \
1577 polymodel *pm = model_get(s_check->modelnum); \
1579 switch((int)frand_range(0.0f, 3.9f)){ \
1581 new_obj->pos.x += 200.0f; \
1584 new_obj->pos.x -= 200.0f; \
1587 new_obj->pos.y += 200.0f; \
1590 new_obj->pos.y -= 200.0f; \
1593 new_obj->pos.z -= 200.0f; \
1599 // process cheat codes
1600 void game_process_cheats(int k)
1609 // no cheats in multiplayer, ever
1610 if(Game_mode & GM_MULTIPLAYER){
1615 k = key_to_ascii(k);
1617 for (i = 0; i < CHEAT_BUFFER_LEN; i++){
1618 CheatBuffer[i]=CheatBuffer[i+1];
1621 CheatBuffer[CHEATSPOT]=(char)k;
1623 cryptstring=jcrypt(&CheatBuffer[CHEAT_BUFFER_LEN - CRYPT_STRING_LENGTH]);
1626 if ( !strcmp(Cheat_code_demo, cryptstring) ) {
1627 HUD_printf(XSTR( "Cheats enabled.", 31));
1629 if (Player->flags & PLAYER_FLAGS_MSG_MODE){
1630 hud_squadmsg_toggle();
1635 if( !strcmp(Cheat_code, cryptstring) && !(Game_mode & GM_MULTIPLAYER)){
1637 HUD_printf("Cheats enabled");
1639 if( !strcmp(Cheat_code_fish, cryptstring) ){
1640 // only enable in the main hall
1641 if((gameseq_get_state() == GS_STATE_MAIN_MENU) && (main_hall_id() == 1)){
1642 extern void fishtank_start();
1646 if( !strcmp(Cheat_code_headz, cryptstring) ){
1647 main_hall_vasudan_funny();
1649 if( !strcmp(Cheat_code_skip, cryptstring) && (gameseq_get_state() == GS_STATE_MAIN_MENU)){
1650 extern void main_hall_campaign_cheat();
1651 main_hall_campaign_cheat();
1653 if( !strcmp(Cheat_code_tooled, cryptstring) && (Game_mode & GM_IN_MISSION)){
1655 HUD_printf("Prepare to be taken to school");
1657 if( !strcmp(Cheat_code_pirate, cryptstring) && (Game_mode & GM_IN_MISSION) && (Player_obj != NULL)){
1658 HUD_printf(NOX("Walk the plank"));
1660 for(int idx=0; idx<1; idx++){
1661 vector add = Player_obj->pos;
1662 add.x += frand_range(-700.0f, 700.0f);
1663 add.y += frand_range(-700.0f, 700.0f);
1664 add.z += frand_range(-700.0f, 700.0f);
1666 int objnum = ship_create(&vmd_identity_matrix, &add, Num_ship_types - 1);
1673 object *new_obj = &Objects[objnum];
1676 // now make sure we're not colliding with anyone
1679 moveup = GET_FIRST(&Ship_obj_list);
1680 while(moveup!=END_OF_LIST(&Ship_obj_list)){
1681 // don't check the new_obj itself!!
1682 if(moveup->objnum != objnum){
1683 hit_check = &Objects[moveup->objnum];
1684 Assert(hit_check->type == OBJ_SHIP);
1685 Assert(hit_check->instance >= 0);
1686 if((hit_check->type != OBJ_SHIP) || (hit_check->instance < 0)){
1689 s_check = &Ships[hit_check->instance];
1691 // just to make sure we don't get any strange magnitude errors
1692 if(vm_vec_same(&hit_check->pos, &Objects[objnum].pos)){
1693 Objects[objnum].pos.x += 1.0f;
1703 moveup = GET_NEXT(moveup);
1708 shipfx_warpin_start(&Objects[objnum]);
1710 // tell him to attack
1711 // ai_add_ship_goal_player( AIG_TYPE_PLAYER_SHIP, AI_GOAL_CHASE_ANY, SM_ATTACK, NULL, &Ai_info[Ships[Objects[objnum].instance].ai_index] );
1717 //#ifdef INTERPLAYQA
1718 if ( !strcmp(Cheat_code_in_game, cryptstring) ) {
1719 HUD_printf(XSTR( "Cheats enabled.", 31));
1721 if (Player->flags & PLAYER_FLAGS_MSG_MODE){
1722 hud_squadmsg_toggle();
1724 } else if ( !strcmp(Cheat_code_movies, cryptstring) ) {
1725 HUD_printf(XSTR( "All movies available in Tech Room", 32));
1726 All_movies_enabled = 1;
1727 if (Player->flags & PLAYER_FLAGS_MSG_MODE){
1728 hud_squadmsg_toggle();
1730 } else if( !strcmp(Cheat_code_pirate, cryptstring) ){
1731 HUD_printf(NOX("Walk the plank"));
1733 for(int idx=0; idx<1; idx++){
1735 add.x = frand_range(-1000.0f, 1000.0f);
1736 add.y = frand_range(-1000.0f, 1000.0f);
1737 add.z = frand_range(-1000.0f, 1000.0f);
1739 int objnum = ship_create(&vmd_identity_matrix, &add, Num_ship_types - 1);
1742 shipfx_warpin_start(&Objects[objnum]);
1750 void game_process_keys()
1754 button_info_clear(&Player->bi); // clear out the button info struct for the player
1758 // AL 12-10-97: Scan for keys used to leave the dead state (don't process any)
1759 // DB 1-13-98 : New popup code will run the game do state, so we must skip
1760 // all key processing in this function, since everything should be run through the popup dialog
1761 if ( Game_mode & GM_DEAD_BLEW_UP ) {
1765 game_process_cheats( k );
1767 // mwa -- 4/5/97 Moved these two function calls before the switch statement. I don't think
1768 // that this has adverse affect on anything and is acutally desireable because of the
1769 // ESC key being used to quit any HUD message/input mode that might be currently in use
1770 process_player_ship_keys(k);
1773 process_debug_keys(k); // Note, also processed for cheats.
1782 if ( Player->control_mode != PCM_NORMAL ) {
1783 if ( Player->control_mode == PCM_WARPOUT_STAGE1 ) {
1784 gameseq_post_event( GS_EVENT_PLAYER_WARPOUT_STOP );
1786 // too late to abort warp out!
1789 // let the ESC key break out of messaging mode
1790 if ( Players[Player_num].flags & PLAYER_FLAGS_MSG_MODE ) {
1791 hud_squadmsg_toggle();
1795 // if in external view or chase view, go back to cockpit view
1796 if ( Viewer_mode & (VM_EXTERNAL|VM_CHASE|VM_OTHER_SHIP) ) {
1797 Viewer_mode &= ~(VM_EXTERNAL|VM_CHASE|VM_OTHER_SHIP);
1801 if (!(Game_mode & GM_DEAD_DIED))
1802 game_do_end_mission_popup();
1813 case KEY_ALTED + KEY_SHIFTED+KEY_J:
1814 // treat the current joystick position as the center position
1818 case KEY_DEBUGGED | KEY_PAUSE:
1819 gameseq_post_event( GS_EVENT_DEBUG_PAUSE_GAME );
1823 game_process_pause_key();
1828 button_info_do(&Player->bi); // call functions based on status of button_info bit vectors
1831 int button_function_critical(int n, net_player *p = NULL)
1836 int at_self; // flag indicating the object is local (for hud messages, etc)
1840 // multiplayer clients should leave critical button bits alone and pass them to the server instead
1841 if ((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER)) {
1842 // if this flag is set, we should apply the button itself (came from the server)
1843 if (!Multi_button_info_ok){
1848 // in single player mode make sure we're using the player object and the player himself, otherwise use the object and
1849 // player pertaining to the passed net_player
1854 if(Game_mode & GM_MULTIPLAYER){
1857 // if we're the server in multiplayer and we're an observer, don't process our own critical button functions
1858 if((Net_player->flags & NETINFO_FLAG_AM_MASTER) && (Net_player->flags & NETINFO_FLAG_OBSERVER)){
1864 objp = &Objects[p->player->objnum];
1869 if ( NETPLAYER_IS_DEAD(npl) || (Ships[Objects[pl->objnum].instance].flags & SF_DYING) )
1874 // cycle to next secondary weapon
1875 case CYCLE_SECONDARY:
1877 control_used(CYCLE_SECONDARY);
1879 hud_gauge_popup_start(HUD_WEAPONS_GAUGE);
1880 if (ship_select_next_secondary(objp)) {
1881 ship* shipp = &Ships[objp->instance];
1882 if ( timestamp_elapsed(shipp->weapons.next_secondary_fire_stamp[shipp->weapons.current_secondary_bank]) ) {
1883 shipp->weapons.next_secondary_fire_stamp[shipp->weapons.current_secondary_bank] = timestamp(250); // 1/4 second delay until can fire
1886 // multiplayer server should maintain bank/link status here
1887 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
1888 Assert(npl != NULL);
1889 multi_server_update_player_weapons(npl,shipp);
1894 // cycle number of missiles
1895 case CYCLE_NUM_MISSLES:
1897 control_used(CYCLE_NUM_MISSLES);
1899 if ( objp == Player_obj ) {
1900 if ( Player_ship->weapons.num_secondary_banks <= 0 ) {
1901 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "This ship has no secondary weapons", 33));
1902 gamesnd_play_iface(SND_GENERAL_FAIL);
1907 if ( Ships[objp->instance].flags & SF_SECONDARY_DUAL_FIRE ) {
1908 Ships[objp->instance].flags &= ~SF_SECONDARY_DUAL_FIRE;
1910 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Secondary weapon set to normal fire mode", 34));
1911 snd_play( &Snds[SND_SECONDARY_CYCLE] );
1912 hud_gauge_popup_start(HUD_WEAPONS_GAUGE);
1915 Ships[objp->instance].flags |= SF_SECONDARY_DUAL_FIRE;
1917 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Secondary weapon set to dual fire mode", 35));
1918 snd_play( &Snds[SND_SECONDARY_CYCLE] );
1919 hud_gauge_popup_start(HUD_WEAPONS_GAUGE);
1923 // multiplayer server should maintain bank/link status here
1924 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
1925 Assert(npl != NULL);
1926 multi_server_update_player_weapons(npl,&Ships[objp->instance]);
1930 // increase weapon recharge rate
1931 case INCREASE_WEAPON:
1933 control_used(INCREASE_WEAPON);
1934 increase_recharge_rate(objp, WEAPONS);
1936 // multiplayer server should maintain bank/link status here
1937 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
1938 Assert(npl != NULL);
1939 multi_server_update_player_weapons(npl,&Ships[objp->instance]);
1943 // decrease weapon recharge rate
1944 case DECREASE_WEAPON:
1946 control_used(DECREASE_WEAPON);
1947 decrease_recharge_rate(objp, WEAPONS);
1949 // multiplayer server should maintain bank/link status here
1950 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
1951 Assert(npl != NULL);
1952 multi_server_update_player_weapons(npl,&Ships[objp->instance]);
1956 // increase shield recharge rate
1957 case INCREASE_SHIELD:
1959 control_used(INCREASE_SHIELD);
1960 increase_recharge_rate(objp, SHIELDS);
1962 // multiplayer server should maintain bank/link status here
1963 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
1964 Assert(npl != NULL);
1965 multi_server_update_player_weapons(npl,&Ships[objp->instance]);
1969 // decrease shield recharge rate
1970 case DECREASE_SHIELD:
1972 control_used(DECREASE_SHIELD);
1973 decrease_recharge_rate(objp, SHIELDS);
1975 // multiplayer server should maintain bank/link status here
1976 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
1977 Assert(npl != NULL);
1978 multi_server_update_player_weapons(npl,&Ships[objp->instance]);
1982 // increase energy to engines
1983 case INCREASE_ENGINE:
1985 control_used(INCREASE_ENGINE);
1986 increase_recharge_rate(objp, ENGINES);
1988 // multiplayer server should maintain bank/link status here
1989 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
1990 Assert(npl != NULL);
1991 multi_server_update_player_weapons(npl,&Ships[objp->instance]);
1995 // decrease energy to engines
1996 case DECREASE_ENGINE:
1998 control_used(DECREASE_ENGINE);
1999 decrease_recharge_rate(objp, ENGINES);
2001 // multiplayer server should maintain bank/link status here
2002 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
2003 Assert(npl != NULL);
2004 multi_server_update_player_weapons(npl,&Ships[objp->instance]);
2008 // equalize recharge rates
2011 control_used(ETS_EQUALIZE);
2014 set_default_recharge_rates(objp);
2015 snd_play( &Snds[SND_ENERGY_TRANS] );
2016 // multiplayer server should maintain bank/link status here
2017 if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
2018 Assert(npl != NULL);
2019 multi_server_update_player_weapons(npl,&Ships[objp->instance]);
2023 // equalize shield energy to all quadrants
2024 case SHIELD_EQUALIZE:
2026 control_used(SHIELD_EQUALIZE);
2028 hud_shield_equalize(objp, pl);
2031 // transfer shield energy to front
2032 case SHIELD_XFER_TOP:
2034 control_used(SHIELD_XFER_TOP);
2036 hud_augment_shield_quadrant(objp, 1);
2039 // transfer shield energy to rear
2040 case SHIELD_XFER_BOTTOM:
2042 control_used(SHIELD_XFER_BOTTOM);
2043 hud_augment_shield_quadrant(objp, 2);
2046 // transfer shield energy to left
2047 case SHIELD_XFER_LEFT:
2049 control_used(SHIELD_XFER_LEFT);
2050 hud_augment_shield_quadrant(objp, 3);
2053 // transfer shield energy to right
2054 case SHIELD_XFER_RIGHT:
2056 control_used(SHIELD_XFER_RIGHT);
2057 hud_augment_shield_quadrant(objp, 0);
2060 // transfer energy to shield from weapons
2063 control_used(XFER_SHIELD);
2064 transfer_energy_to_shields(objp);
2067 // transfer energy to weapons from shield
2070 control_used(XFER_LASER);
2071 transfer_energy_to_weapons(objp);
2074 // following are not handled here, but we need to bypass the Int3()
2075 case LAUNCH_COUNTERMEASURE:
2078 case VIEW_EXTERNAL_TOGGLE_CAMERA_LOCK:
2079 case ONE_THIRD_THROTTLE:
2080 case TWO_THIRDS_THROTTLE:
2081 case MINUS_5_PERCENT_THROTTLE:
2082 case PLUS_5_PERCENT_THROTTLE:
2088 Int3(); // bad bad bad
2095 // return !0 if the action is allowed, otherwise return 0
2096 int button_allowed(int n)
2098 if ( hud_disabled() ) {
2102 case CYCLE_NEXT_PRIMARY:
2103 case CYCLE_PREV_PRIMARY:
2104 case CYCLE_SECONDARY:
2105 case ONE_THIRD_THROTTLE:
2106 case TWO_THIRDS_THROTTLE:
2107 case PLUS_5_PERCENT_THROTTLE:
2108 case MINUS_5_PERCENT_THROTTLE:
2120 // execute function corresponding to action n
2121 // basically, these are actions which don't affect demo playback at all
2122 int button_function_demo_valid(int n)
2124 // by default, we'll return "not processed". ret will get set to 1, if this is one of the keys which is always allowed, even in demo
2128 // No keys, not even targeting keys, when player in death roll. He can press keys after he blows up.
2129 if (Game_mode & GM_DEAD_DIED){
2133 // any of these buttons are valid
2136 control_used(VIEW_CHASE);
2137 Viewer_mode ^= VM_CHASE;
2138 if ( Viewer_mode & VM_CHASE ) {
2139 Viewer_mode &= ~VM_EXTERNAL;
2145 control_used(VIEW_EXTERNAL);
2146 Viewer_mode ^= VM_EXTERNAL;
2147 Viewer_mode &= ~VM_EXTERNAL_CAMERA_LOCKED; // reset camera lock when leave/entering external view
2148 if ( Viewer_mode & VM_EXTERNAL ) {
2149 Viewer_mode &= ~VM_CHASE;
2154 case VIEW_EXTERNAL_TOGGLE_CAMERA_LOCK:
2155 control_used(VIEW_EXTERNAL_TOGGLE_CAMERA_LOCK);
2156 if ( Viewer_mode & VM_EXTERNAL ) {
2157 Viewer_mode ^= VM_EXTERNAL_CAMERA_LOCKED;
2158 if ( Viewer_mode & VM_EXTERNAL_CAMERA_LOCKED ) {
2159 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "External camera is locked, controls will move ship", 36));
2161 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "External camera is free, controls will move the camera, not the ship", 37));
2167 case VIEW_OTHER_SHIP:
2168 control_used(VIEW_OTHER_SHIP);
2169 if ( Player_ai->target_objnum < 0 ) {
2170 snd_play( &Snds[SND_TARGET_FAIL] );
2172 if ( Objects[Player_ai->target_objnum].type != OBJ_SHIP ) {
2173 snd_play( &Snds[SND_TARGET_FAIL] );
2175 Viewer_mode ^= VM_OTHER_SHIP;
2181 case TIME_SLOW_DOWN:
2182 if ( Game_mode & GM_NORMAL ) {
2183 if ( Game_time_compression > F1_0) {
2184 Game_time_compression /= 2;
2186 gamesnd_play_error_beep();
2189 gamesnd_play_error_beep();
2195 if ( Game_mode & GM_NORMAL ) {
2196 if ( Game_time_compression < (F1_0*4) ) {
2197 Game_time_compression *= 2;
2199 gamesnd_play_error_beep();
2202 gamesnd_play_error_beep();
2212 // execute function corresponding to action n (BUTTON_ #define from KeyControl.h)
2213 int button_function(int n)
2217 if ( !button_allowed(n) ) {
2221 // No keys, not even targeting keys, when player in death roll. He can press keys after he blows up.
2222 if (Game_mode & GM_DEAD_DIED){
2227 // cycle to next primary weapon
2228 case CYCLE_NEXT_PRIMARY:
2230 if((Player_obj == NULL) || (Player_ship == NULL)){
2234 hud_gauge_popup_start(HUD_WEAPONS_GAUGE);
2235 if (ship_select_next_primary(Player_obj, CYCLE_PRIMARY_NEXT)) {
2236 ship* shipp = Player_ship;
2237 shipp->weapons.next_primary_fire_stamp[shipp->weapons.current_primary_bank] = timestamp(250); // 1/4 second delay until can fire
2238 // multiplayer server should maintain bank/link status here
2239 // if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
2240 // Assert(npl != NULL);
2241 // multi_server_update_player_weapons(npl,shipp);
2246 // cycle to previous primary weapon
2247 case CYCLE_PREV_PRIMARY:
2249 if((Player_obj == NULL) || (Player_ship == NULL)){
2253 hud_gauge_popup_start(HUD_WEAPONS_GAUGE);
2254 if (ship_select_next_primary(Player_obj, CYCLE_PRIMARY_PREV)) {
2255 ship* shipp = Player_ship;
2256 shipp->weapons.next_primary_fire_stamp[shipp->weapons.current_primary_bank] = timestamp(250); // 1/4 second delay until can fire
2258 // multiplayer server should maintain bank/link status here
2259 // if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){
2260 // Assert(npl != NULL);
2261 // multi_server_update_player_weapons(npl,shipp);
2266 // cycle to next secondary weapon
2267 case CYCLE_SECONDARY:
2268 return button_function_critical(CYCLE_SECONDARY);
2271 // cycle number of missiles fired from secondary bank
2272 case CYCLE_NUM_MISSLES:
2273 return button_function_critical(CYCLE_NUM_MISSLES);
2276 // undefined in multiplayer for clients right now
2277 // match target speed
2278 case MATCH_TARGET_SPEED:
2279 control_used(MATCH_TARGET_SPEED);
2280 // If player is auto-matching, break auto-match speed
2281 if ( Player->flags & PLAYER_FLAGS_AUTO_MATCH_SPEED ) {
2282 Player->flags &= ~PLAYER_FLAGS_AUTO_MATCH_SPEED;
2284 player_match_target_speed();
2287 // undefined in multiplayer for clients right now
2288 // toggle auto-match target speed
2289 case TOGGLE_AUTO_MATCH_TARGET_SPEED:
2290 // multiplayer observers can't match target speed
2291 if((Game_mode & GM_MULTIPLAYER) && (Net_player != NULL) && ((Net_player->flags & NETINFO_FLAG_OBSERVER) || (Player_obj->type == OBJ_OBSERVER)) ){
2295 Player->flags ^= PLAYER_FLAGS_AUTO_MATCH_SPEED;
2296 control_used(TOGGLE_AUTO_MATCH_TARGET_SPEED);
2297 hud_gauge_popup_start(HUD_AUTO_SPEED);
2298 if ( Players[Player_num].flags & PLAYER_FLAGS_AUTO_MATCH_SPEED ) {
2299 snd_play(&Snds[SND_SHIELD_XFER_OK], 1.0f);
2300 // HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Auto match target speed activated", -1));
2301 if ( !Player->flags & PLAYER_FLAGS_MATCH_TARGET ) {
2302 player_match_target_speed();
2306 // HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Auto match target deactivated", -1));
2307 snd_play(&Snds[SND_SHIELD_XFER_OK], 1.0f);
2308 player_match_target_speed();
2314 control_used(TARGET_NEXT);
2315 if ( hud_sensors_ok(Player_ship) ) {
2322 control_used(TARGET_PREV);
2323 if ( hud_sensors_ok(Player_ship) ) {
2328 // target the next hostile target
2329 case TARGET_NEXT_CLOSEST_HOSTILE:
2330 control_used(TARGET_NEXT_CLOSEST_HOSTILE);
2331 if (hud_sensors_ok(Player_ship)){
2332 hud_target_next_list();
2336 // target the previous closest hostile
2337 case TARGET_PREV_CLOSEST_HOSTILE:
2338 control_used(TARGET_PREV_CLOSEST_HOSTILE);
2339 if (hud_sensors_ok(Player_ship)){
2340 hud_target_next_list(1,0);
2344 // toggle auto-targeting
2345 case TOGGLE_AUTO_TARGETING:
2346 control_used(TOGGLE_AUTO_TARGETING);
2347 hud_gauge_popup_start(HUD_AUTO_TARGET);
2348 Players[Player_num].flags ^= PLAYER_FLAGS_AUTO_TARGETING;
2349 if ( Players[Player_num].flags & PLAYER_FLAGS_AUTO_TARGETING ) {
2350 if (hud_sensors_ok(Player_ship)) {
2351 hud_target_closest(opposing_team_mask(Player_ship->team), -1, FALSE, TRUE );
2352 snd_play(&Snds[SND_SHIELD_XFER_OK], 1.0f);
2353 // HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Auto targeting activated", -1));
2355 Players[Player_num].flags ^= PLAYER_FLAGS_AUTO_TARGETING;
2358 snd_play(&Snds[SND_SHIELD_XFER_OK], 1.0f);
2359 // HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Auto targeting deactivated", -1));
2363 // target the next friendly ship
2364 case TARGET_NEXT_CLOSEST_FRIENDLY:
2365 control_used(TARGET_NEXT_CLOSEST_FRIENDLY);
2366 if (hud_sensors_ok(Player_ship)){
2367 hud_target_next_list(0);
2371 // target the closest friendly ship
2372 case TARGET_PREV_CLOSEST_FRIENDLY:
2373 control_used(TARGET_PREV_CLOSEST_FRIENDLY);
2374 if (hud_sensors_ok(Player_ship)) {
2375 hud_target_next_list(0,0);
2379 // target ship closest to center of reticle
2380 case TARGET_SHIP_IN_RETICLE:
2381 control_used(TARGET_SHIP_IN_RETICLE);
2382 if (hud_sensors_ok(Player_ship)){
2383 hud_target_in_reticle_new();
2387 case TARGET_LAST_TRANMISSION_SENDER:
2388 control_used(TARGET_LAST_TRANMISSION_SENDER);
2389 if ( hud_sensors_ok(Player_ship)) {
2390 hud_target_last_transmit();
2394 // target the closest repair ship
2395 case TARGET_CLOSEST_REPAIR_SHIP:
2396 control_used(TARGET_CLOSEST_REPAIR_SHIP);
2397 // AL: Try to find the closest repair ship coming to repair the player... if no support
2398 // ships are coming to rearm the player, just try for the closest repair ship
2399 if ( hud_target_closest_repair_ship(OBJ_INDEX(Player_obj)) == 0 ) {
2400 if ( hud_target_closest_repair_ship() == 0 ) {
2401 snd_play(&Snds[SND_TARGET_FAIL]);
2406 // target the closest ship attacking current target
2407 case TARGET_CLOSEST_SHIP_ATTACKING_TARGET:
2408 control_used(TARGET_CLOSEST_SHIP_ATTACKING_TARGET);
2409 if (hud_sensors_ok(Player_ship)){
2410 hud_target_closest(opposing_team_mask(Player_ship->team), Player_ai->target_objnum);
2414 // stop targeting ship
2415 case STOP_TARGETING_SHIP:
2416 control_used(STOP_TARGETING_SHIP);
2417 hud_cease_targeting();
2420 // target closest ship that is attacking player
2421 case TARGET_CLOSEST_SHIP_ATTACKING_SELF:
2422 control_used(TARGET_CLOSEST_SHIP_ATTACKING_SELF);
2423 if (hud_sensors_ok(Player_ship)){
2424 hud_target_closest(opposing_team_mask(Player_ship->team), OBJ_INDEX(Player_obj), TRUE, 0, 1);
2428 // target your target's target
2429 case TARGET_TARGETS_TARGET:
2430 control_used(TARGET_TARGETS_TARGET);
2431 if (hud_sensors_ok(Player_ship)){
2432 hud_target_targets_target();
2436 // target ships subsystem in reticle
2437 case TARGET_SUBOBJECT_IN_RETICLE:
2438 control_used(TARGET_SUBOBJECT_IN_RETICLE);
2439 if (hud_sensors_ok(Player_ship)){
2440 hud_target_subsystem_in_reticle();
2444 case TARGET_PREV_SUBOBJECT:
2445 control_used(TARGET_PREV_SUBOBJECT);
2446 if (hud_sensors_ok(Player_ship)){
2447 hud_target_prev_subobject();
2451 // target next subsystem on current target
2452 case TARGET_NEXT_SUBOBJECT:
2453 control_used(TARGET_NEXT_SUBOBJECT);
2454 if (hud_sensors_ok(Player_ship)){
2455 hud_target_next_subobject();
2459 // stop targeting subsystems on ship
2460 case STOP_TARGETING_SUBSYSTEM:
2461 control_used(STOP_TARGETING_SUBSYSTEM);
2462 hud_cease_subsystem_targeting();
2465 case TARGET_NEXT_BOMB:
2466 control_used(TARGET_NEXT_BOMB);
2467 hud_target_missile(Player_obj, 1);
2470 case TARGET_PREV_BOMB:
2471 control_used(TARGET_PREV_BOMB);
2472 hud_target_missile(Player_obj, 0);
2475 case TARGET_NEXT_UNINSPECTED_CARGO:
2476 hud_target_uninspected_object(1);
2479 case TARGET_PREV_UNINSPECTED_CARGO:
2480 hud_target_uninspected_object(0);
2483 case TARGET_NEWEST_SHIP:
2484 hud_target_newest_ship();
2487 case TARGET_NEXT_LIVE_TURRET:
2488 hud_target_live_turret(1);
2491 case TARGET_PREV_LIVE_TURRET:
2492 hud_target_live_turret(0);
2495 // wingman message: attack current target
2496 case ATTACK_MESSAGE:
2497 control_used(ATTACK_MESSAGE);
2498 hud_squadmsg_shortcut( ATTACK_TARGET_ITEM );
2501 // wingman message: disarm current target
2502 case DISARM_MESSAGE:
2503 control_used(DISARM_MESSAGE);
2504 hud_squadmsg_shortcut( DISARM_TARGET_ITEM );
2507 // wingman message: disable current target
2508 case DISABLE_MESSAGE:
2509 control_used(DISABLE_MESSAGE);
2510 hud_squadmsg_shortcut( DISABLE_TARGET_ITEM );
2513 // wingman message: disable current target
2514 case ATTACK_SUBSYSTEM_MESSAGE:
2515 control_used(ATTACK_SUBSYSTEM_MESSAGE);
2516 hud_squadmsg_shortcut( DISABLE_SUBSYSTEM_ITEM );
2519 // wingman message: capture current target
2520 case CAPTURE_MESSAGE:
2521 control_used(CAPTURE_MESSAGE);
2522 hud_squadmsg_shortcut( CAPTURE_TARGET_ITEM );
2525 // wingman message: engage enemy
2526 case ENGAGE_MESSAGE:
2527 control_used(ENGAGE_MESSAGE);
2528 hud_squadmsg_shortcut( ENGAGE_ENEMY_ITEM );
2531 // wingman message: form on my wing
2533 control_used(FORM_MESSAGE);
2534 hud_squadmsg_shortcut( FORMATION_ITEM );
2537 // wingman message: protect current target
2538 case PROTECT_MESSAGE:
2539 control_used(PROTECT_MESSAGE);
2540 hud_squadmsg_shortcut( PROTECT_TARGET_ITEM );
2543 // wingman message: cover me
2545 control_used(COVER_MESSAGE);
2546 hud_squadmsg_shortcut( COVER_ME_ITEM );
2549 // wingman message: warp out
2551 control_used(WARP_MESSAGE);
2552 hud_squadmsg_shortcut( DEPART_ITEM );
2555 case IGNORE_MESSAGE:
2556 control_used(IGNORE_MESSAGE);
2557 hud_squadmsg_shortcut( IGNORE_TARGET_ITEM );
2562 control_used(REARM_MESSAGE);
2563 hud_squadmsg_rearm_shortcut();
2566 // cycle to next radar range
2567 case RADAR_RANGE_CYCLE:
2568 control_used(RADAR_RANGE_CYCLE);
2569 HUD_config.rp_dist++;
2570 if ( HUD_config.rp_dist >= RR_MAX_RANGES )
2571 HUD_config.rp_dist = 0;
2573 HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Radar range set to %s", 38), Radar_range_text(HUD_config.rp_dist));
2576 // toggle the squadmate messaging menu
2578 control_used(SQUADMSG_MENU);
2579 hud_squadmsg_toggle(); // leave the details to the messaging code!!!
2582 // show the mission goals screen
2584 control_used(SHOW_GOALS);
2585 gameseq_post_event( GS_EVENT_SHOW_GOALS );
2590 // in multiplayer, all end mission requests should go through the server
2591 if(Game_mode & GM_MULTIPLAYER){
2592 multi_handle_end_mission_request();
2596 control_used(END_MISSION);
2598 if (collide_predict_large_ship(Player_obj, 200.0f)) {
2599 gamesnd_play_iface(SND_GENERAL_FAIL);
2600 HUD_printf(XSTR( "** WARNING ** Collision danger. Warpout not activated.", 39));
2601 } else if (ship_get_subsystem_strength( Player_ship, SUBSYSTEM_ENGINE ) < 0.1f) {
2602 gamesnd_play_iface(SND_GENERAL_FAIL);
2603 HUD_printf(XSTR( "Engine failure. Cannot engage warp drive.", 40));
2605 gameseq_post_event( GS_EVENT_PLAYER_WARPOUT_START );
2609 case ADD_REMOVE_ESCORT:
2610 if ( Player_ai->target_objnum >= 0 ) {
2611 control_used(ADD_REMOVE_ESCORT);
2612 hud_add_remove_ship_escort(Player_ai->target_objnum);
2617 control_used(ESCORT_CLEAR);
2618 hud_escort_clear_all();
2621 case TARGET_NEXT_ESCORT_SHIP:
2622 control_used(TARGET_NEXT_ESCORT_SHIP);
2623 hud_escort_target_next();
2626 // increase weapon recharge rate
2627 case INCREASE_WEAPON:
2628 hud_gauge_popup_start(HUD_ETS_GAUGE);
2629 return button_function_critical(INCREASE_WEAPON);
2632 // decrease weapon recharge rate
2633 case DECREASE_WEAPON:
2634 hud_gauge_popup_start(HUD_ETS_GAUGE);
2635 return button_function_critical(DECREASE_WEAPON);
2638 // increase shield recharge rate
2639 case INCREASE_SHIELD:
2640 hud_gauge_popup_start(HUD_ETS_GAUGE);
2641 return button_function_critical(INCREASE_SHIELD);
2644 // decrease shield recharge rate
2645 case DECREASE_SHIELD:
2646 hud_gauge_popup_start(HUD_ETS_GAUGE);
2647 return button_function_critical(DECREASE_SHIELD);
2650 // increase energy to engines
2651 case INCREASE_ENGINE:
2652 hud_gauge_popup_start(HUD_ETS_GAUGE);
2653 return button_function_critical(INCREASE_ENGINE);
2656 // decrease energy to engines
2657 case DECREASE_ENGINE:
2658 hud_gauge_popup_start(HUD_ETS_GAUGE);
2659 return button_function_critical(DECREASE_ENGINE);
2663 hud_gauge_popup_start(HUD_ETS_GAUGE);
2664 return button_function_critical(ETS_EQUALIZE);
2667 // equalize shield energy to all quadrants
2668 case SHIELD_EQUALIZE:
2669 return button_function_critical(SHIELD_EQUALIZE);
2672 // transfer shield energy to front
2673 case SHIELD_XFER_TOP:
2674 return button_function_critical(SHIELD_XFER_TOP);
2677 // transfer shield energy to rear
2678 case SHIELD_XFER_BOTTOM:
2679 return button_function_critical(SHIELD_XFER_BOTTOM);
2682 // transfer shield energy to left
2683 case SHIELD_XFER_LEFT:
2684 return button_function_critical(SHIELD_XFER_LEFT);
2687 // transfer shield energy to right
2688 case SHIELD_XFER_RIGHT:
2689 return button_function_critical(SHIELD_XFER_RIGHT);
2692 // transfer energy to shield from weapons
2694 return button_function_critical(XFER_SHIELD);
2697 // transfer energy to weapons from shield
2699 return button_function_critical(XFER_LASER);
2702 // message all netplayers button
2703 case MULTI_MESSAGE_ALL:
2704 multi_msg_key_down(MULTI_MSG_ALL);
2707 // message all friendlies button
2708 case MULTI_MESSAGE_FRIENDLY:
2709 multi_msg_key_down(MULTI_MSG_FRIENDLY);
2712 // message all hostiles button
2713 case MULTI_MESSAGE_HOSTILE:
2714 multi_msg_key_down(MULTI_MSG_HOSTILE);
2717 // message targeted ship (if player)
2718 case MULTI_MESSAGE_TARGET:
2719 multi_msg_key_down(MULTI_MSG_TARGET);
2722 // if i'm an observer, zoom to my targeted object
2723 case MULTI_OBSERVER_ZOOM_TO:
2724 multi_obs_zoom_to_target();
2727 // toggle between high and low HUD contrast
2728 case TOGGLE_HUD_CONTRAST:
2729 gamesnd_play_iface(SND_USER_SELECT);
2730 hud_toggle_contrast();
2733 // toggle network info
2734 case MULTI_TOGGLE_NETINFO:
2735 extern int Multi_display_netinfo;
2736 Multi_display_netinfo = !Multi_display_netinfo;
2739 // self destruct (multiplayer only)
2740 case MULTI_SELF_DESTRUCT:
2741 if(!(Game_mode & GM_MULTIPLAYER)){
2746 if((Net_player == NULL) || (Net_player->player == NULL)){
2750 // blow myself up, if I'm the server
2751 if(Net_player->flags & NETINFO_FLAG_AM_MASTER){
2752 if((Net_player->player->objnum >= 0) && (Net_player->player->objnum < MAX_OBJECTS) &&
2753 (Objects[Net_player->player->objnum].type == OBJ_SHIP) && (Objects[Net_player->player->objnum].instance >= 0) && (Objects[Net_player->player->objnum].instance < MAX_SHIPS)){
2755 ship_self_destruct(&Objects[Net_player->player->objnum]);
2758 // otherwise send a packet to the server
2760 send_self_destruct_packet();
2764 // following are not handled here, but we need to bypass the Int3()
2765 case LAUNCH_COUNTERMEASURE:
2767 case ONE_THIRD_THROTTLE:
2768 case TWO_THIRDS_THROTTLE:
2769 case MINUS_5_PERCENT_THROTTLE:
2770 case PLUS_5_PERCENT_THROTTLE:
2783 // Call functions for when buttons are pressed
2784 void button_info_do(button_info *bi)
2788 for (i=0; i<NUM_BUTTON_FIELDS; i++) {
2789 if ( bi->status[i] == 0 ){
2793 // at least one bit is set in the status integer
2794 for (j=0; j<32; j++) {
2796 // check if the bit is set. If button_function returns 1 (implying the action was taken), then unset the bit
2797 if ( bi->status[i] & (1 << j) ) {
2798 // always process buttons which are valid for demo playback
2799 if(button_function_demo_valid(32 * i + j)){
2800 bi->status[i] &= ~(1 << j);
2804 // if we're in demo playback, always clear the bits
2805 if(Game_mode & GM_DEMO_PLAYBACK){
2806 bi->status[i] &= ~(1 << j);
2808 // otherwise check as normal
2809 else if (button_function(32 * i + j)) {
2810 bi->status[i] &= ~(1 << j);
2819 // set the bit for the corresponding action n (BUTTON_ #define from KeyControl.h)
2820 void button_info_set(button_info *bi, int n)
2822 int field_num, bit_num;
2827 bi->status[field_num] |= (1 << bit_num);
2830 // unset the bit for the corresponding action n (BUTTON_ #define from KeyControl.h)
2831 void button_info_unset(button_info *bi, int n)
2833 int field_num, bit_num;
2838 bi->status[field_num] &= ~(1 << bit_num);
2841 int button_info_query(button_info *bi, int n)
2843 return bi->status[n / 32] & (1 << (n % 32));
2846 // clear out the button_info struct
2847 void button_info_clear(button_info *bi)
2851 for (i=0; i<NUM_BUTTON_FIELDS; i++) {
2856 // strip out all noncritical keys from the button info struct
2857 void button_strip_noncritical_keys(button_info *bi)
2861 // clear out all noncritical keys
2862 for(idx=0;idx<Non_critical_key_set_size;idx++){
2863 button_info_unset(bi,Non_critical_key_set[idx]);