/* * Copyright (C) Volition, Inc. 1999. All rights reserved. * * All source code herein is the property of Volition, Inc. You may not sell * or otherwise commercially exploit the source or things you created based on the * source. * */ /* * $Logfile: /Freespace2/code/Io/KeyControl.cpp $ * $Revision: 2.68 $ * $Date: 2006-01-13 03:31:09 $ * $Author: Goober5000 $ * * Routines to read and deal with keyboard input. * * $Log: not supported by cvs2svn $ * Revision 2.67 2005/12/29 08:08:36 wmcoolmon * Codebase commit, most notably including objecttypes.tbl * * Revision 2.66 2005/12/04 19:07:48 wmcoolmon * Final commit of codebase * * Revision 2.65 2005/11/24 08:46:11 Goober5000 * * cleaned up mission_do_departure * * fixed a hidden crash (array index being -1; would only * be triggered for ships w/o subspace drives under certain conditions) * * removed finding a new fighterbay target because it might screw up missions * * improved clarity, code flow, and readability :) * * added custom AI flag for disabling warpouts if navigation subsystem fails * --Goober5000 * * Revision 2.64 2005/11/23 06:53:22 taylor * when using cheats be sure to properly load up all weapons that aren't already paged in * * Revision 2.63 2005/10/11 07:43:10 wmcoolmon * Topdown updates * * Revision 2.62 2005/10/11 05:24:34 wmcoolmon * Gliding * * Revision 2.61 2005/10/10 17:14:31 taylor * remove NO_NETWORK * fix controlconfig so that axes can be set to joystick/mouse using the mouse (required when no joystick attached) * * Revision 2.60 2005/09/27 06:39:23 Goober5000 * small fix, bah * --Goober5000 * * Revision 2.59 2005/09/25 08:25:15 Goober5000 * Okay, everything should now work again. :p Still have to do a little more with the asteroids. * --Goober5000 * * Revision 2.58 2005/09/25 05:13:06 Goober5000 * hopefully complete species upgrade * --Goober5000 * * Revision 2.57 2005/09/24 07:07:16 Goober5000 * another species overhaul * --Goober5000 * * Revision 2.56 2005/07/22 10:18:39 Goober5000 * CVS header tweaks * --Goober5000 * * Revision 2.55 2005/07/13 03:15:52 Goober5000 * remove PreProcDefine #includes in FS2 * --Goober5000 * * Revision 2.54 2005/07/13 02:30:53 Goober5000 * removed autopilot #define * --Goober5000 * * Revision 2.53 2005/07/13 02:01:29 Goober5000 * fixed a bunch of "issues" caused by me with the species stuff * --Goober5000 * * Revision 2.52 2005/07/13 00:44:22 Goober5000 * improved species support and removed need for #define * --Goober5000 * * Revision 2.51 2005/04/25 00:23:23 wmcoolmon * MAX_SHIP_CLASSES > Num_ship_classes * * Revision 2.50 2005/04/20 04:34:01 phreak * get the cheat keys for "force weapon" working again * * Revision 2.49 2005/04/05 05:53:18 taylor * s/vector/vec3d/g, better support for different compilers (Jens Granseuer) * * Revision 2.48 2005/03/27 13:23:05 Goober5000 * rewrote the weapon cheat cycle functions to avoid recursion * --Goober5000 * * Revision 2.47 2005/03/27 12:28:33 Goober5000 * clarified max hull/shield strength names and added ship guardian thresholds * --Goober5000 * * Revision 2.46 2005/03/27 04:16:19 wmcoolmon * Fixed possible infinite loop problem * * Revision 2.45 2005/03/25 06:57:34 wmcoolmon * Big, massive, codebase commit. I have not removed the old ai files as the ones I uploaded aren't up-to-date (But should work with the rest of the codebase) * * Revision 2.44 2005/03/03 06:05:28 wmcoolmon * Merge of WMC's codebase. "Features and bugs, making Goober say "Grr!", as release would be stalled now for two months for sure" * * Revision 2.43 2005/03/02 21:24:41 taylor * more network/inferno goodness for Windows, takes care of a few warnings too * * Revision 2.42 2005/02/21 05:40:16 Goober5000 * restored release version of some cheat codes; removed a cheat for cloaking * --Goober5000 * * Revision 2.41 2005/02/20 05:22:44 Goober5000 * restored original behavior for cheat code time dilation * --Goober5000 * * Revision 2.40 2005/02/04 10:12:30 taylor * merge with Linux/OSX tree - p0204 * * Revision 2.39 2005/01/16 22:39:09 wmcoolmon * Added VM_TOPDOWN view; Added 2D mission mode, add 16384 to mission +Flags to use. * * Revision 2.38 2004/09/28 19:54:32 Kazan * | is binary or, || is boolean or - please use the right one * autopilot velocity ramping biasing * made debugged+k kill guardianed ships * * Revision 2.37 2004/08/26 18:19:36 Kazan * small standalone-related multibug fix * prohibited execution of process_debug_keys(int) while Game_mode & GM_MULTIPLAYER * * Revision 2.36 2004/07/29 19:37:50 Kazan * unbug the JS bug i caused --- kazan * * Revision 2.35 2004/07/26 20:47:33 Kazan * remove MCD complete * * Revision 2.34 2004/07/25 00:31:29 Kazan * i have absolutely nothing to say about that subject * * Revision 2.33 2004/07/12 16:32:51 Kazan * MCD - define _MCD_CHECK to use memory tracking * * Revision 2.32 2004/07/12 03:19:16 Kazan * removed a couple pointless useless messages from the debug console * * Revision 2.31 2004/05/10 10:51:53 Goober5000 * made primary and secondary banks quite a bit more friendly... added error-checking * and reorganized a bunch of code * --Goober5000 * * Revision 2.30 2004/05/10 06:11:47 Goober5000 * fixed warp decision * --Goober5000 * * Revision 2.29 2004/05/03 21:22:21 Kazan * Abandon strdup() usage for mod list processing - it was acting odd and causing crashing on free() * Fix condition where alt_tab_pause() would flipout and trigger failed assert if game minimizes during startup (like it does a lot during debug) * Nav Point / Auto Pilot code (All disabled via #ifdefs) * * Revision 2.28 2004/04/26 19:50:04 Goober5000 * added back in Kazan's line: now you can slow down in cheat mode * whether you press tilde or not * --Goober5000 * * Revision 2.27 2004/04/26 19:43:07 Goober5000 * rolled back Kazan's change * --Goober5000 * * Revision 2.25 2004/04/25 06:31:53 Goober5000 * made time dilation only available in cheat mode; also fixed an obscure CTD * --Goober5000 * * Revision 2.24 2004/04/24 15:44:21 Kazan * Fixed Lobby screen showing up while exiting from non-tracker games * Time dialiation up to 1/4 * * Revision 2.23 2004/04/06 03:09:26 phreak * added a control config option for the wireframe hud targetbox i enabled ages ago * * Revision 2.22 2004/04/06 01:11:41 Kazan * make custom build work again * * Revision 2.21 2004/03/05 09:02:04 Goober5000 * Uber pass at reducing #includes * --Goober5000 * * Revision 2.20 2004/01/30 07:39:07 Goober5000 * whew - I just went through all the code I ever added (or at least, that I could * find that I commented with a Goober5000 tag) and added a bunch of Asserts * and error-checking * --Goober5000 * * Revision 2.19 2004/01/14 06:38:41 Goober5000 * fixx0red a bug * --Goober5000 * * Revision 2.18 2003/10/15 22:03:25 Kazan * Da Species Update :D * * Revision 2.17 2003/09/26 14:37:14 bobboau * commiting Hardware T&L code, everything is ifdefed out with the compile flag HTL * still needs a lot of work, ubt the frame rates were getting with it are incredable * the biggest problem it still has is a bad lightmanegment system, and the zbuffer * doesn't work well with things still getting rendered useing the sofware pipeline, like thrusters, * and weapons, I think these should be modifyed to be sent through hardware, * it would be slightly faster and it would likely fix the problem * * also the thruster glow/particle stuff I did is now in. * * Revision 2.16 2003/09/13 06:02:06 Goober5000 * clean rollback of all of argv's stuff * --Goober5000 * * Revision 2.14 2003/08/16 03:52:23 bobboau * update for the specmapping code includeing * suport for seperate specular levels on lights and * optional strings for the stars table * code has been made more organised, * though there seems to be a bug in the state selecting code * resulting in the HUD being rendered incorectly * and specmapping failing ocasionaly * * Revision 2.13 2003/08/05 23:45:18 bobboau * glow maps, for some reason they wern't in here, they should be now, * also there is some debug code for changeing the FOV in game, * and I have some changes to the init code to try and get a 32 or 24 bit back buffer * if posable, this may cause problems for people * the changes were all marked and if needed can be undone * * Revision 2.12 2003/07/15 02:35:59 phreak * added a debug key to cloak targeted ship ~+shift+x * * Revision 2.11 2003/07/04 02:26:15 phreak * tilde + x cloaks a ship * * Revision 2.10 2003/04/29 01:03:23 Goober5000 * implemented the custom hitpoints mod * --Goober5000 * * Revision 2.9 2003/01/18 10:00:43 Goober5000 * added "no-subspace-drive" flag for ships * --Goober5000 * * Revision 2.8 2003/01/03 21:58:08 Goober5000 * Fixed some minor bugs, and added a primitive-sensors flag, where if a ship * has primitive sensors it can't target anything and objects don't appear * on radar if they're outside a certain range. This range can be modified * via the sexp primitive-sensors-set-range. * --Goober5000 * * Revision 2.7 2002/12/31 18:59:43 Goober5000 * if it ain't broke, don't fix it * --Goober5000 * * Revision 2.5 2002/12/10 05:43:34 Goober5000 * Full-fledged ballistic primary support added! Try it and see! :) * * Revision 2.4 2002/10/19 03:50:29 randomtiger * Added special pause mode for easier action screenshots. * Added new command line parameter for accessing all single missions in tech room. - RT * * Revision 2.3 2002/10/17 20:40:51 randomtiger * Added ability to remove HUD ingame on keypress shift O * So I've added a new key to the bind list and made use of already existing hud removal code. * * Revision 2.2 2002/08/06 16:49:22 phreak * added keybing for wireframe hud, * fixed previous missile cheat * * * Revision 2.2 2002/08/04 23:15:40 PhReAk * Fixed previous missile cheat, commented out beam_test(x) lines * in process_debug_keys(). beam_test(x) caused assertion failure in * beam.cpp apprx line 3147. Also added toggle for wire_hud in process_player_ship_keys() * * Revision 2.1 2002/08/01 01:41:06 penguin * The big include file move * * Revision 2.0 2002/06/03 04:02:24 penguin * Warpcore CVS sync * * Revision 1.5 2002/05/26 14:13:19 mharris * Debugging * * Revision 1.4 2002/05/24 16:45:45 mharris * Added some debug mprintfs * * Revision 1.3 2002/05/17 03:03:14 mharris * Porting fixes: changes to matrix and vector structs; added * NO_NETWORK and NO_SOUND where appropriate. * * Revision 1.2 2002/05/13 21:43:38 mharris * A little more network and sound cleanup * * Revision 1.1 2002/05/02 18:03:08 mharris * Initial checkin - converted filenames and includes to lower case * * * 47 9/09/99 11:40p Dave * Handle an Assert() in beam code. Added supernova sounds. Play the right * 2 end movies properly, based upon what the player did in the mission. * * 46 9/07/99 11:26p Andsager * Fix "r" targeting key, making evaluate_ship_as_closest_target() and * hud_target_live_turret() consider if turret is targeting player * * 45 9/03/99 1:31a Dave * CD checking by act. Added support to play 2 cutscenes in a row * seamlessly. Fixed super low level cfile bug related to files in the * root directory of a CD. Added cheat code to set campaign mission # in * main hall. * * 44 9/01/99 10:09a Dave * Pirate bob. * * 43 8/27/99 10:36a Dave * Impose a 2% penalty for hitting the shield balance key. * * 42 8/27/99 9:57a Dave * Enabled standard cheat codes. Allow player to continue in a campaing * after using cheat codes. * * 41 8/26/99 9:45a Dave * First pass at easter eggs and cheats. * * 40 8/24/99 1:49a Dave * Fixed client-side afterburner stuttering. Added checkbox for no version * checking on PXO join. Made button info passing more friendly between * client and server. * * 39 8/22/99 5:53p Dave * Scoring fixes. Added self destruct key. Put callsigns in the logfile * instead of ship designations for multiplayer players. * * 38 8/19/99 10:59a Dave * Packet loss detection. * * 37 8/18/99 12:09p Andsager * Add debug if message has no anim for message. Make messages come from * wing leader. * * 36 8/05/99 2:05a Dave * Whee. * * 35 8/01/99 12:39p Dave * Added HUD contrast control key (for nebula). * * 34 7/31/99 2:30p Dave * Added nifty mission message debug viewing keys. * * 33 7/21/99 8:10p Dave * First run of supernova effect. * * 32 7/15/99 4:09p Andsager * Disable cheats for FS2_DEMO * * 31 7/15/99 9:20a Andsager * FS2_DEMO initial checkin * * 30 7/07/99 3:32p Dave * Oops. Forgot to remove this. * * 29 7/02/99 4:31p Dave * Much more sophisticated lightning support. * * 28 6/10/99 3:43p Dave * Do a better job of syncing text colors to HUD gauges. * * 27 6/09/99 2:55p Andsager * Allow multiple asteroid subtypes (of large, medium, small) and follow * family. * * 26 5/24/99 5:45p Dave * Added detail levels to the nebula, with a decent speedup. Split nebula * lightning into its own section. * * 25 5/08/99 8:25p Dave * Upped object pairs. First run of nebula lightning. * * 24 5/05/99 9:02p Dave * Fixed D3D aabitmap rendering. Spiffed up nebula effect a bit (added * rotations, tweaked values, made bitmap selection more random). Fixed * D3D beam weapon clipping problem. Added D3d frame dumping. * * 23 5/03/99 9:07a Dave * Pirate Bob. Changed beam test code a bit. * * 22 4/21/99 6:15p Dave * Did some serious housecleaning in the beam code. Made it ready to go * for anti-fighter "pulse" weapons. Fixed collision pair creation. Added * a handy macro for recalculating collision pairs for a given object. * * 21 4/16/99 5:54p Dave * Support for on/off style "stream" weapons. Real early support for * target-painting lasers. * * 20 3/31/99 8:24p Dave * Beefed up all kinds of stuff, incluging beam weapons, nebula effects * and background nebulae. Added per-ship non-dimming pixel colors. * * 19 3/29/99 6:17p Dave * More work on demo system. Got just about everything in except for * blowing ships up, secondary weapons and player death/warpout. * * 18 3/28/99 5:58p Dave * Added early demo code. Make objects move. Nice and framerate * independant, but not much else. Don't use yet unless you're me :) * * 17 3/09/99 6:24p Dave * More work on object update revamping. Identified several sources of * unnecessary bandwidth. * * 16 2/21/99 6:01p Dave * Fixed standalone WSS packets. * * 15 2/21/99 1:48p Dave * Some code for monitoring datarate for multiplayer in detail. * * 14 1/21/99 2:06p Dave * Final checkin for multiplayer testing. * * 13 1/19/99 3:57p Andsager * Round 2 of variables * * 12 1/12/99 12:53a Dave * More work on beam weapons - made collision detection very efficient - * collide against all object types properly - made 3 movement types * smooth. Put in test code to check for possible non-darkening pixels on * object textures. * * 11 1/08/99 2:08p Dave * Fixed software rendering for pofview. Super early support for AWACS and * beam weapons. * * 10 12/06/98 2:36p Dave * Drastically improved nebula fogging. * * 9 12/04/98 3:37p Andsager * Added comment out asteroid launcher * * 8 11/19/98 4:19p Dave * Put IPX sockets back in psnet. Consolidated all multiplayer config * files into one. * * 7 11/05/98 5:55p Dave * Big pass at reducing #includes * * 6 10/26/98 9:42a Dave * Early flak gun support. * * 5 10/20/98 1:39p Andsager * Make so sparks follow animated ship submodels. Modify * ship_weapon_do_hit_stuff() and ship_apply_local_damage() to add * submodel_num. Add submodel_num to multiplayer hit packet. * * 4 10/13/98 9:28a Dave * Started neatening up freespace.h. Many variables renamed and * reorganized. Added AlphaColors.[h,cpp] * * 3 10/09/98 2:57p Dave * Starting splitting up OS stuff. * * 2 10/07/98 10:53a Dave * Initial checkin. * * 1 10/07/98 10:49a Dave * * 387 6/17/98 11:02a Lawrance * show what cheat code is in the comment * * 386 6/09/98 5:15p Lawrance * French/German localization * * 385 6/09/98 10:31a Hoffoss * Created index numbers for all xstr() references. Any new xstr() stuff * added from here on out should be added to the end if the list. The * current list count can be found in FreeSpace.cpp (search for * XSTR_SIZE). * * 384 6/01/98 11:43a John * JAS & MK: Classified all strings for localization. * * 383 5/24/98 1:46p Mike * Final cheat codes. * * 382 5/19/98 2:20p Mike * Comment out nprintf(). * * 381 5/19/98 12:19p Mike * Cheat codes! * * 380 5/19/98 11:11a Lawrance * Make 'G' only target hostiles * * 379 5/18/98 11:00p Mike * Adding support for cheat system. * * 378 5/18/98 12:41a Allender * fixed subsystem problems on clients (i.e. not reporting properly on * damage indicator). Fixed ingame join problem with respawns. minor * comm menu stuff * * 377 5/17/98 1:43a Dave * Eradicated chatbox problems. Remove speed match for observers. Put in * help screens for PXO. Fix messaging and end mission privelges. Fixed * team select screen bugs. Misc UI fixes. * * 376 5/15/98 8:36p Lawrance * Add 'target ship that last sent transmission' target key * * 375 5/14/98 11:07a Lawrance * Ensure looped sounds get stopped before stopping all channels * * 374 5/12/98 11:59p Dave * Put in some more functionality for Parallax Online. * * 373 5/11/98 5:29p Hoffoss * Added mouse button mapped to joystick button support. * * 372 5/08/98 10:14a Lawrance * Play sound when auto-targeting gets toggled. * * 371 5/04/98 9:25a Allender * don't allow time compression in multiplayer * * 370 4/30/98 4:43p Allender * trap player obj when changing dual fire status on ship * * 369 4/30/98 4:16p Peter * fixes for critical button functions when a player (client) ship is dead * or dying * * 368 4/27/98 9:03a Dave * Fixed a multiplayer sequencing bug where paused players who were in the * options screen got an Assert when unpausing. Removed an optimiized * build warning in keycontrol. * * 367 4/26/98 4:29p Lawrance * Put back time compression keys... somehow they were trashed by a later * checkin. * * 366 4/25/98 5:36p Mike * Prevent player warpout if engine < 10%. * * $NoKeywords: $ */ #include "globalincs/pstypes.h" #include "globalincs/globals.h" #include "globalincs/linklist.h" #include "io/key.h" #include "io/joy.h" #include "io/timer.h" #include "ship/ship.h" #include "playerman/player.h" #include "weapon/weapon.h" #include "hud/hud.h" #include "gamesequence/gamesequence.h" #include "mission/missiongoals.h" #include "hud/hudets.h" #include "gamesnd/gamesnd.h" #include "hud/hudsquadmsg.h" #include "gamesnd/eventmusic.h" #include "freespace2/freespace.h" #include "mission/missionhotkey.h" #include "hud/hudescort.h" #include "hud/hudshield.h" #include "io/keycontrol.h" #include "ship/shiphit.h" #include "ship/shipfx.h" #include "mission/missionlog.h" #include "hud/hudtargetbox.h" #include "popup/popup.h" #include "object/objcollide.h" #include "object/object.h" #include "hud/hudconfig.h" #include "hud/hudmessage.h" #include "network/multi_pmsg.h" #include "globalincs/crypt.h" #include "starfield/supernova.h" #include "mission/missionmessage.h" #include "menuui/mainhallmenu.h" #include "missionui/missionpause.h" #include "hud/hudgauges.h" #include "freespace2/freespace.h" //For time compression stuff #include "species_defs/species_defs.h" #include "asteroid/asteroid.h" #include "iff_defs/iff_defs.h" #include "network/multi.h" #include "network/multiutil.h" #include "network/multimsgs.h" #include "network/multi_pause.h" #include "network/multi_observer.h" #include "network/multi_endgame.h" #include "autopilot/autopilot.h" // -------------------------------------------------------------- // Global to file // -------------------------------------------------------------- // time compression/dilation values - Goober5000 // (Volition sez "can't compress below 0.25"... not sure if // this is arbitrary or dictated by code) #define MAX_TIME_MULTIPLIER 64 #define MAX_TIME_DIVIDER 4 #define CHEAT_BUFFER_LEN 20 #define CHEATSPOT (CHEAT_BUFFER_LEN - 1) char CheatBuffer[CHEAT_BUFFER_LEN+1]; #ifdef FS2_DEMO char *Cheat_code_demo = NOX("33BE^(8]C01(:=BHt"); #else char *Cheat_code = NOX("33BE^(8]C01(:=BHt"); // www.freespace2.com char *Cheat_code_fish = NOX("bDc9y+$;#AIDRoouM"); // vasudanswuvfishes char *Cheat_code_headz = NOX("!;:::@>F7L?@@2:@A"); // humanheadsinside. char *Cheat_code_tooled = NOX("sipp-^rM@L!U^usjX"); // tooledworkedowned char *Cheat_code_pirate = NOX("MAP4YP[4=-2uC(yJ^"); // arrrrwalktheplank char *Cheat_code_skip = NOX("7!ICkSI\"(8n3JesBP"); // skipmemymissionyo #endif // 666)6=N79+Z45=BE0e int Tool_enabled = 0; bool Perspective_locked=false; /* #else // list of the cheat codes //#ifdef INTERPLAYQA // "DavidPerry" NOX("0!XZQ*K.pu"); // NOX("&BvWJe=a?$VP*=@2W,2Y"); // Super-secret 20 character string! //NOX("STs`nHqW\\lv#KD_aCSWN"); // solveditonceandforall (note double \\ as string contains \. //XSTR:OFF char *Cheat_code_in_game = NOX("///FES)P\\+_(Qs#+h-8o"); // arrwalktheplankmatey //XSTR:ON #endif */ //int All_movies_enabled = 0; //int Debug_allowed = 0; //#endif extern int AI_watch_object; extern int Countermeasures_enabled; extern float do_subobj_hit_stuff(object *ship_obj, object *other_obj, vec3d *hitpos, float damage, bool *hull_should_apply_armor); extern void mission_goal_mark_all_true( int type ); int Normal_key_set[] = { TARGET_NEXT, TARGET_PREV, TARGET_NEXT_CLOSEST_HOSTILE, TARGET_PREV_CLOSEST_HOSTILE, TARGET_NEXT_CLOSEST_FRIENDLY, TARGET_PREV_CLOSEST_FRIENDLY, TARGET_TARGETS_TARGET, TARGET_SHIP_IN_RETICLE, TARGET_LAST_TRANMISSION_SENDER, TARGET_CLOSEST_SHIP_ATTACKING_TARGET, TARGET_CLOSEST_SHIP_ATTACKING_SELF, STOP_TARGETING_SHIP, TOGGLE_AUTO_TARGETING, TARGET_SUBOBJECT_IN_RETICLE, TARGET_PREV_SUBOBJECT, TARGET_NEXT_SUBOBJECT, STOP_TARGETING_SUBSYSTEM, TARGET_NEXT_UNINSPECTED_CARGO, TARGET_PREV_UNINSPECTED_CARGO, TARGET_NEWEST_SHIP, TARGET_NEXT_LIVE_TURRET, TARGET_PREV_LIVE_TURRET, TARGET_NEXT_BOMB, TARGET_PREV_BOMB, ATTACK_MESSAGE, DISARM_MESSAGE, DISABLE_MESSAGE, ATTACK_SUBSYSTEM_MESSAGE, CAPTURE_MESSAGE, ENGAGE_MESSAGE, FORM_MESSAGE, PROTECT_MESSAGE, COVER_MESSAGE, WARP_MESSAGE, REARM_MESSAGE, IGNORE_MESSAGE, SQUADMSG_MENU, VIEW_CHASE, VIEW_OTHER_SHIP, VIEW_TOPDOWN, SHOW_GOALS, END_MISSION, ADD_REMOVE_ESCORT, ESCORT_CLEAR, TARGET_NEXT_ESCORT_SHIP, XFER_SHIELD, XFER_LASER, INCREASE_SHIELD, INCREASE_WEAPON, INCREASE_ENGINE, DECREASE_SHIELD, DECREASE_WEAPON, DECREASE_ENGINE, ETS_EQUALIZE, SHIELD_EQUALIZE, SHIELD_XFER_TOP, SHIELD_XFER_BOTTOM, SHIELD_XFER_RIGHT, SHIELD_XFER_LEFT, CYCLE_NEXT_PRIMARY, CYCLE_PREV_PRIMARY, CYCLE_SECONDARY, CYCLE_NUM_MISSLES, RADAR_RANGE_CYCLE, MATCH_TARGET_SPEED, TOGGLE_AUTO_MATCH_TARGET_SPEED, VIEW_EXTERNAL, VIEW_EXTERNAL_TOGGLE_CAMERA_LOCK, LAUNCH_COUNTERMEASURE, ONE_THIRD_THROTTLE, TWO_THIRDS_THROTTLE, PLUS_5_PERCENT_THROTTLE, MINUS_5_PERCENT_THROTTLE, ZERO_THROTTLE, MAX_THROTTLE, TARGET_CLOSEST_REPAIR_SHIP, MULTI_MESSAGE_ALL, MULTI_MESSAGE_FRIENDLY, MULTI_MESSAGE_HOSTILE, MULTI_MESSAGE_TARGET, MULTI_OBSERVER_ZOOM_TO, TIME_SPEED_UP, TIME_SLOW_DOWN, TOGGLE_HUD_CONTRAST, MULTI_TOGGLE_NETINFO, MULTI_SELF_DESTRUCT, TOGGLE_HUD, HUD_TARGETBOX_TOGGLE_WIREFRAME, AUTO_PILOT_TOGGLE, NAV_CYCLE, TOGGLE_GLIDING }; int Dead_key_set[] = { TARGET_NEXT, TARGET_PREV, TARGET_NEXT_CLOSEST_HOSTILE, TARGET_PREV_CLOSEST_HOSTILE, TARGET_NEXT_CLOSEST_FRIENDLY, TARGET_PREV_CLOSEST_FRIENDLY, TARGET_TARGETS_TARGET, TARGET_CLOSEST_SHIP_ATTACKING_TARGET, STOP_TARGETING_SHIP, TOGGLE_AUTO_TARGETING, TARGET_SUBOBJECT_IN_RETICLE, TARGET_PREV_SUBOBJECT, TARGET_NEXT_SUBOBJECT, STOP_TARGETING_SUBSYSTEM, TARGET_NEWEST_SHIP, TARGET_NEXT_LIVE_TURRET, TARGET_PREV_LIVE_TURRET, TARGET_NEXT_BOMB, TARGET_PREV_BOMB, VIEW_CHASE, VIEW_OTHER_SHIP, VIEW_TOPDOWN, SHOW_GOALS, ADD_REMOVE_ESCORT, ESCORT_CLEAR, TARGET_NEXT_ESCORT_SHIP, TARGET_CLOSEST_REPAIR_SHIP, MULTI_MESSAGE_ALL, MULTI_MESSAGE_FRIENDLY, MULTI_MESSAGE_HOSTILE, MULTI_MESSAGE_TARGET, MULTI_OBSERVER_ZOOM_TO, TIME_SPEED_UP, TIME_SLOW_DOWN }; int Critical_key_set[] = { CYCLE_SECONDARY, CYCLE_NUM_MISSLES, INCREASE_WEAPON, DECREASE_WEAPON, INCREASE_SHIELD, DECREASE_SHIELD, INCREASE_ENGINE, DECREASE_ENGINE, ETS_EQUALIZE, SHIELD_EQUALIZE, SHIELD_XFER_TOP, SHIELD_XFER_BOTTOM, SHIELD_XFER_LEFT, SHIELD_XFER_RIGHT, XFER_SHIELD, XFER_LASER, }; int Non_critical_key_set[] = { CYCLE_NEXT_PRIMARY, CYCLE_PREV_PRIMARY, MATCH_TARGET_SPEED, TOGGLE_AUTO_MATCH_TARGET_SPEED, TARGET_NEXT, TARGET_PREV, TARGET_NEXT_CLOSEST_HOSTILE, TARGET_PREV_CLOSEST_HOSTILE, TOGGLE_AUTO_TARGETING, TARGET_NEXT_CLOSEST_FRIENDLY, TARGET_PREV_CLOSEST_FRIENDLY, TARGET_SHIP_IN_RETICLE, TARGET_LAST_TRANMISSION_SENDER, TARGET_CLOSEST_REPAIR_SHIP, TARGET_CLOSEST_SHIP_ATTACKING_TARGET, STOP_TARGETING_SHIP, TARGET_CLOSEST_SHIP_ATTACKING_SELF, TARGET_TARGETS_TARGET, TARGET_SUBOBJECT_IN_RETICLE, TARGET_PREV_SUBOBJECT, TARGET_NEXT_SUBOBJECT, STOP_TARGETING_SUBSYSTEM, TARGET_NEXT_BOMB, TARGET_PREV_BOMB, TARGET_NEXT_UNINSPECTED_CARGO, TARGET_PREV_UNINSPECTED_CARGO, TARGET_NEWEST_SHIP, TARGET_NEXT_LIVE_TURRET, TARGET_PREV_LIVE_TURRET, ATTACK_MESSAGE, DISARM_MESSAGE, DISABLE_MESSAGE, ATTACK_SUBSYSTEM_MESSAGE, CAPTURE_MESSAGE, ENGAGE_MESSAGE, FORM_MESSAGE, PROTECT_MESSAGE, COVER_MESSAGE, WARP_MESSAGE, IGNORE_MESSAGE, REARM_MESSAGE, VIEW_CHASE, VIEW_EXTERNAL, VIEW_EXTERNAL_TOGGLE_CAMERA_LOCK, VIEW_OTHER_SHIP, VIEW_TOPDOWN, RADAR_RANGE_CYCLE, SQUADMSG_MENU, SHOW_GOALS, END_MISSION, ADD_REMOVE_ESCORT, ESCORT_CLEAR, TARGET_NEXT_ESCORT_SHIP, MULTI_MESSAGE_ALL, MULTI_MESSAGE_FRIENDLY, MULTI_MESSAGE_HOSTILE, MULTI_MESSAGE_TARGET, MULTI_OBSERVER_ZOOM_TO, TOGGLE_HUD_CONTRAST, MULTI_TOGGLE_NETINFO, MULTI_SELF_DESTRUCT, TOGGLE_HUD, HUD_TARGETBOX_TOGGLE_WIREFRAME, AUTO_PILOT_TOGGLE, NAV_CYCLE, TOGGLE_GLIDING }; // set sizes of the key sets automatically int Normal_key_set_size = sizeof(Normal_key_set) / sizeof(int); int Dead_key_set_size = sizeof(Dead_key_set) / sizeof(int); int Critical_key_set_size = sizeof(Critical_key_set) / sizeof(int); int Non_critical_key_set_size = sizeof(Non_critical_key_set) / sizeof(int); // -------------------------------------------------------------- // routine to process keys used only for debugging // -------------------------------------------------------------- //#ifndef NDEBUG void debug_cycle_player_ship(int delta) { if ( Player_obj == NULL ) return; int si_index = Ships[Player_obj->instance].ship_info_index; int sanity = 0; ship_info *sip; while ( TRUE ) { si_index += delta; if ( si_index > Num_ship_classes ){ si_index = 0; } if ( si_index < 0 ){ si_index = Num_ship_classes - 1; } sip = &Ship_info[si_index]; if ( sip->flags & SIF_PLAYER_SHIP ){ break; } // just in case sanity++; if ( sanity > Num_ship_classes ){ break; } } change_ship_type(Player_obj->instance, si_index); HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Player ship changed to %s", 0), Ship_info[si_index].name); } // cycle targeted ship to next ship in that species void debug_cycle_targeted_ship(int delta) { object *objp; ship_info *sip; int si_index, species; char name[NAME_LENGTH]; if ( Player_ai->target_objnum == -1 ) return; objp = &Objects[Player_ai->target_objnum]; if ( objp->type != OBJ_SHIP ) return; si_index = Ships[objp->instance].ship_info_index; Assert(si_index != -1 ); species = Ship_info[si_index].species; int sanity = 0; while ( TRUE ) { si_index += delta; if ( si_index > Num_ship_classes ) si_index = 0; if ( si_index < 0 ) si_index = Num_ship_classes-1; sip = &Ship_info[si_index]; // if it has test in the name, jump over it strcpy(name, sip->name); _strlwr(name); if ( strstr(name,NOX("test")) != NULL ) continue; if ( sip->species == species && (sip->flags & (SIF_FIGHTER | SIF_BOMBER | SIF_TRANSPORT) ) ) break; // just in case sanity++; if ( sanity > Num_ship_classes ) break; } change_ship_type(objp->instance, si_index); HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Changed player target to %s", 1), Ship_info[si_index].name); } void debug_max_secondary_weapons(object *objp) { int index; ship *shipp = &Ships[objp->instance]; ship_info *sip = &Ship_info[shipp->ship_info_index]; ship_weapon *swp = &shipp->weapons; for ( index = 0; index < MAX_SHIP_SECONDARY_BANKS; index++ ) { swp->secondary_bank_ammo[index] = sip->secondary_bank_ammo_capacity[index]; } } void debug_max_primary_weapons(object *objp) // Goober5000 { Assert(objp); // Goober5000 int index; ship *shipp = &Ships[objp->instance]; ship_info *sip = &Ship_info[shipp->ship_info_index]; ship_weapon *swp = &shipp->weapons; weapon_info *wip; if (sip->flags & SIF_BALLISTIC_PRIMARIES) { for ( index = 0; index < MAX_SHIP_PRIMARY_BANKS; index++ ) { wip = &Weapon_info[swp->primary_bank_weapons[index]]; if (wip->wi_flags2 & WIF2_BALLISTIC) { swp->primary_bank_ammo[index] = sip->primary_bank_ammo_capacity[index]; } } } } void debug_change_song(int delta) { #ifndef NO_SOUND char buf[256]; if ( event_music_next_soundtrack(delta) != -1 ) { event_music_get_soundtrack_name(buf); HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Soundtrack changed to: %s", 2), buf); } else { HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Event music is not playing", 3)); } #endif } //extern void set_global_ignore_object(int objnum); extern void hud_target_asteroid(); extern int Framerate_delay; extern void snd_stop_any_sound(); extern float Viewer_zoom; extern vec3d Eye_position; extern matrix Eye_matrix; extern void g3_set_view_matrix(vec3d *view_pos,matrix *view_matrix,float zoom); extern int Show_cpu; int get_prev_weapon_looped(int current_weapon, int subtype) { int i, new_index; for (i = 1; i < Num_weapon_types; i++) { new_index = (Num_weapon_types + current_weapon - i) % Num_weapon_types; if(Weapon_info[new_index].subtype == subtype) { return new_index; } } return current_weapon; } int get_next_weapon_looped(int current_weapon, int subtype) { int i, new_index; for (i = 1; i < Num_weapon_types; i++) { new_index = (current_weapon + i) % Num_weapon_types; if(Weapon_info[new_index].subtype == subtype) { return new_index; } } return current_weapon; } extern int Num_species; void process_debug_keys(int k) { #ifdef INTERPLAYQA if ( !Debug_allowed ) return; #endif // Kazan -- NO CHEATS IN MULTIb if (Game_mode & GM_MULTIPLAYER) { return; } // if ( (k & KEY_DEBUGGED) && (Game_mode & GM_RECORDING_DEMO) ) // return; switch (k) { case KEY_DEBUGGED + KEY_H: hud_target_toggle_hidden_from_sensors(); break; case KEY_DEBUGGED + KEY_F: /* int i; for (i=0; icallsign); break; case KEY_DEBUGGED + KEY_C: case KEY_DEBUGGED1 + KEY_C: // hud_enemymsg_toggle(); if(Player_obj->flags & OF_COLLIDES){ obj_set_flags(Player_obj, Player_obj->flags & ~(OF_COLLIDES)); HUD_sourced_printf(HUD_SOURCE_HIDDEN, "Player no longer collides"); } else { obj_set_flags(Player_obj, Player_obj->flags | OF_COLLIDES); HUD_sourced_printf(HUD_SOURCE_HIDDEN, "Player collides"); } break; case KEY_DEBUGGED + KEY_SHIFTED + KEY_C: case KEY_DEBUGGED1 + KEY_SHIFTED + KEY_C: Countermeasures_enabled = !Countermeasures_enabled; HUD_printf(XSTR( "Countermeasure firing: %s", 6), Countermeasures_enabled ? XSTR( "ENABLED", 7) : XSTR( "DISABLED", 8)); break; // Goober5000: this should only be compiled in debug builds, since it crashes release #ifndef NDEBUG case KEY_DEBUGGED + KEY_E: gameseq_post_event(GS_EVENT_EVENT_DEBUG); break; #endif // Goober5000: handle time dilation in cheat section case KEY_DEBUGGED + KEY_SHIFTED + KEY_COMMA: case KEY_DEBUGGED1 + KEY_SHIFTED + KEY_COMMA: if ( Game_mode & GM_NORMAL ) { if ( Game_time_compression > (F1_0/MAX_TIME_DIVIDER) ) { change_time_compression(0.5); } else { gamesnd_play_error_beep(); } } else { gamesnd_play_error_beep(); } break; // Goober5000: handle as normal here case KEY_DEBUGGED + KEY_SHIFTED + KEY_PERIOD: case KEY_DEBUGGED1 + KEY_SHIFTED + KEY_PERIOD: if ( Game_mode & GM_NORMAL ) { if ( Game_time_compression < (F1_0*MAX_TIME_MULTIPLIER) ) { change_time_compression(2); } else { gamesnd_play_error_beep(); } } else { gamesnd_play_error_beep(); } break; // Kill! the currently targeted ship. case KEY_DEBUGGED + KEY_K: case KEY_DEBUGGED1 + KEY_K: if (Player_ai->target_objnum != -1) { object *objp = &Objects[Player_ai->target_objnum]; switch (objp->type) { case OBJ_SHIP: // remove guardian flag -- kazan Ships[objp->instance].ship_guardian_threshold = 0; ship_apply_local_damage( objp, Player_obj, &objp->pos, 100000.0f, MISS_SHIELDS, CREATE_SPARKS); ship_apply_local_damage( objp, Player_obj, &objp->pos, 1.0f, MISS_SHIELDS, CREATE_SPARKS); break; case OBJ_WEAPON: Weapons[objp->instance].lifeleft = 0.01f; break; } } break; // play the next mission message case KEY_DEBUGGED + KEY_V: extern int Message_debug_index; extern int Num_messages_playing; // stop any other messages if(Num_messages_playing){ message_kill_all(1); } // next message if(Message_debug_index >= Num_messages - 1){ Message_debug_index = Num_builtin_messages; } else { Message_debug_index++; } // play the message 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 ); if (Messages[Message_debug_index].avi_info.index == -1) { HUD_printf("No anim set for message \"%s\"; None will play!", Messages[Message_debug_index].name); } break; // play the previous mission message case KEY_DEBUGGED + KEY_SHIFTED + KEY_V: extern int Message_debug_index; extern int Num_messages_playing; // stop any other messages if(Num_messages_playing){ message_kill_all(1); } // go maybe go down one if(Message_debug_index == Num_builtin_messages - 1){ Message_debug_index = Num_builtin_messages; } else if(Message_debug_index > Num_builtin_messages){ Message_debug_index--; } // play the message 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 ); if (Messages[Message_debug_index].avi_info.index == -1) { HUD_printf("No avi associated with this message; None will play!"); } break; // reset to the beginning of mission messages case KEY_DEBUGGED + KEY_ALTED + KEY_V: extern int Message_debug_index; Message_debug_index = Num_builtin_messages - 1; HUD_printf("Resetting to first mission message"); break; // Kill! the currently targeted ship. case KEY_DEBUGGED + KEY_ALTED + KEY_SHIFTED + KEY_K: case KEY_DEBUGGED1 + KEY_ALTED + KEY_SHIFTED + KEY_K: if (Player_ai->target_objnum != -1) { object *objp = &Objects[Player_ai->target_objnum]; if (objp->type == OBJ_SHIP) { ship_apply_local_damage( objp, Player_obj, &objp->pos, Ships[objp->instance].ship_max_hull_strength * 0.1f + 10.0f, MISS_SHIELDS, CREATE_SPARKS); } } break; // Kill the currently targeted subsystem. case KEY_DEBUGGED + KEY_SHIFTED + KEY_K: case KEY_DEBUGGED1 + KEY_SHIFTED + KEY_K: if ((Player_ai->target_objnum != -1) && (Player_ai->targeted_subsys != NULL)) { object *objp = &Objects[Player_ai->target_objnum]; if ( objp->type == OBJ_SHIP ) { ship *sp = &Ships[objp->instance]; vec3d g_subobj_pos; get_subsystem_world_pos(objp, Player_ai->targeted_subsys, &g_subobj_pos); do_subobj_hit_stuff(objp, Player_obj, &g_subobj_pos, (float) -Player_ai->targeted_subsys->system_info->type, NULL); //100.0f); if ( sp->subsys_info[SUBSYSTEM_ENGINE].current_hits <= 0.0f ) { mission_log_add_entry(LOG_SHIP_DISABLED, sp->ship_name, NULL ); sp->flags |= SF_DISABLED; // add the disabled flag } if ( sp->subsys_info[SUBSYSTEM_TURRET].current_hits <= 0.0f ) { mission_log_add_entry(LOG_SHIP_DISARMED, sp->ship_name, NULL ); // sp->flags |= SF_DISARMED; // add the disarmed flag } } } break; case KEY_DEBUGGED + KEY_ALTED + KEY_K: case KEY_DEBUGGED1 + KEY_ALTED + KEY_K: { float shield, integrity; vec3d pos, randvec; vm_vec_rand_vec_quick(&randvec); vm_vec_scale_add(&pos, &Player_obj->pos, &randvec, Player_obj->radius); ship_apply_local_damage(Player_obj, Player_obj, &pos, 25.0f, MISS_SHIELDS, CREATE_SPARKS); hud_get_target_strength(Player_obj, &shield, &integrity); HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "You knocked yourself down to %7.3f percent hull.\n", 9), 100.0f * integrity); break; } // Whack down the player's shield and hull by a little more than 50% // Select next object to be viewed by AI. case KEY_DEBUGGED + KEY_I: case KEY_DEBUGGED1 + KEY_I: Player_obj->flags ^= OF_INVULNERABLE; 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)); break; case KEY_DEBUGGED + KEY_SHIFTED + KEY_I: case KEY_DEBUGGED1 + KEY_SHIFTED + KEY_I: if (Player_ai->target_objnum != -1) { object *objp = &Objects[Player_ai->target_objnum]; objp->flags ^= OF_INVULNERABLE; 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)); } break; /* case KEY_DEBUGGED + KEY_ALTED + KEY_I: if (Player_ai->target_objnum != -1) set_global_ignore_object(Player_ai->target_objnum); break; */ case KEY_DEBUGGED + KEY_N: AI_watch_object++; HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Spewing debug info about object #%d", 14), AI_watch_object); break; case KEY_DEBUGGED + KEY_O: case KEY_DEBUGGED1 + KEY_O: toggle_player_object(); break; case KEY_DEBUGGED + KEY_SHIFTED + KEY_O: extern int Debug_octant; if(Debug_octant == 7){ Debug_octant = -1; } else { Debug_octant++; } nprintf(("General", "Debug_octant == %d\n", Debug_octant)); break; case KEY_DEBUGGED + KEY_P: supernova_start(20); break; case KEY_DEBUGGED + KEY_W: case KEY_DEBUGGED1 + KEY_W: case KEY_DEBUGGED + KEY_SHIFTED + KEY_W: case KEY_DEBUGGED1 + KEY_SHIFTED + KEY_W: // temp code for testing purposes, toggles weapon energy cheat Weapon_energy_cheat = !Weapon_energy_cheat; if (Weapon_energy_cheat) { if (k & KEY_SHIFTED) HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Weapon energy and missile count will always be at full ALL SHIPS!", 15)); else HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Weapon energy and missile count will always be at full for player", 16)); debug_max_secondary_weapons(Player_obj); debug_max_primary_weapons(Player_obj); if (k & KEY_SHIFTED) { object *objp; for ( objp = GET_FIRST(&obj_used_list); objp !=END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp) ) if (objp->type == OBJ_SHIP) debug_max_secondary_weapons(objp); debug_max_primary_weapons(objp); } } else HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Normal weapon energy system / missile count restored", 17)); break; case KEY_DEBUGGED + KEY_G: case KEY_DEBUGGED1 + KEY_G: mission_goal_mark_all_true( PRIMARY_GOAL ); break; case KEY_DEBUGGED + KEY_G + KEY_SHIFTED: case KEY_DEBUGGED1 + KEY_G + KEY_SHIFTED: mission_goal_mark_all_true( SECONDARY_GOAL ); break; case KEY_DEBUGGED + KEY_G + KEY_ALTED: case KEY_DEBUGGED1 + KEY_G + KEY_ALTED: mission_goal_mark_all_true( BONUS_GOAL ); break; case KEY_DEBUGGED + KEY_9: { case KEY_DEBUGGED1 + KEY_9: ship* shipp; shipp = &Ships[Player_obj->instance]; int *weap = &shipp->weapons.secondary_bank_weapons[shipp->weapons.current_secondary_bank]; *weap = get_next_weapon_looped(*weap, WP_MISSILE); HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Secondary Weapon forced to %s", 18), Weapon_info[*weap].name); break; } case KEY_DEBUGGED + KEY_SHIFTED + KEY_9: { case KEY_DEBUGGED1 + KEY_SHIFTED + KEY_9: ship* shipp; shipp = &Ships[Player_obj->instance]; int *weap = &shipp->weapons.secondary_bank_weapons[shipp->weapons.current_secondary_bank]; *weap = get_prev_weapon_looped(*weap, WP_MISSILE); HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Secondary Weapon forced to %s", 18), Weapon_info[*weap].name); break; } #ifndef FS2_DEMO case KEY_DEBUGGED + KEY_U: { case KEY_DEBUGGED1 + KEY_U: // launch asteroid object *asteroid_create(asteroid_field *asfieldp, int asteroid_type, int subtype); object *objp = asteroid_create(&Asteroid_field, 0, 0); vec3d vel; vm_vec_copy_scale(&vel, &Player_obj->orient.vec.fvec, 50.0f); objp->phys_info.vel = vel; objp->phys_info.desired_vel = vel; objp->pos = Player_obj->pos; //mission_goal_mark_all_true( PRIMARY_GOAL ); break; } #endif case KEY_DEBUGGED + KEY_0: { case KEY_DEBUGGED1 + KEY_0: ship* shipp; shipp = &Ships[Player_obj->instance]; int *weap = &shipp->weapons.primary_bank_weapons[shipp->weapons.current_primary_bank]; *weap = get_next_weapon_looped(*weap, WP_LASER); HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Primary Weapon forced to %s", 19), Weapon_info[*weap].name); break; } case KEY_DEBUGGED + KEY_SHIFTED + KEY_0: { case KEY_DEBUGGED1 + KEY_SHIFTED + KEY_0: ship* shipp; shipp = &Ships[Player_obj->instance]; int *weap = &shipp->weapons.primary_bank_weapons[shipp->weapons.current_primary_bank]; *weap = get_prev_weapon_looped(*weap, WP_LASER); HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Primary Weapon forced to %s", 19), Weapon_info[*weap].name); break; } #ifndef NO_SOUND case KEY_DEBUGGED + KEY_J: { int new_pattern = event_music_return_current_pattern(); new_pattern++; if ( new_pattern >= MAX_PATTERNS ) new_pattern = 0; event_music_change_pattern(new_pattern); break; } case KEY_DEBUGGED + KEY_M: { if ( Event_music_enabled ) { event_music_disable(); HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Event music disabled", 20)); } else { event_music_enable(); HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Event music enabled", 21)); } break; } #endif case KEY_DEBUGGED + KEY_R: { case KEY_DEBUGGED1 + KEY_R: if (Player_ai->target_objnum != -1) ai_issue_rearm_request(&Objects[Player_ai->target_objnum]); else ai_issue_rearm_request(Player_obj); break; } case KEY_DEBUGGED + KEY_SHIFTED + KEY_UP: Game_detail_level++; HUD_printf( XSTR( "Detail level set to %+d\n", 22), Game_detail_level ); break; case KEY_DEBUGGED + KEY_SHIFTED + KEY_DOWN: Game_detail_level--; HUD_printf( XSTR( "Detail level set to %+d\n", 22), Game_detail_level ); break; #ifndef NDEBUG case KEY_DEBUGGED + KEY_SHIFTED + KEY_T: { extern int Test_begin; if ( Test_begin == 1 ) break; Test_begin = 1; HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Frame Rate test started", 23)); break; } #endif case KEY_DEBUGGED + KEY_A: { HUD_printf("frame rate currently is %0.2 FPS", 1/flFrametime); break; } case KEY_DEBUGGED + KEY_D: extern int OO_update_index; if(MULTIPLAYER_MASTER){ do { OO_update_index++; } while((OO_update_index < (MAX_PLAYERS-1)) && !MULTI_CONNECTED(Net_players[OO_update_index])); if(OO_update_index >= MAX_PLAYERS-1){ OO_update_index = -1; } } else { if(OO_update_index < 0){ OO_update_index = MY_NET_PLAYER_NUM; } else { OO_update_index = -1; } } break; // change player ship to next flyable type case KEY_DEBUGGED + KEY_RIGHT: debug_cycle_player_ship(1); break; // change player ship to previous flyable ship case KEY_DEBUGGED + KEY_LEFT: debug_cycle_player_ship(-1); break; // cycle target to ship case KEY_DEBUGGED + KEY_SHIFTED + KEY_RIGHT: debug_cycle_targeted_ship(1); break; // cycle target to previous ship case KEY_DEBUGGED + KEY_SHIFTED + KEY_LEFT: debug_cycle_targeted_ship(-1); break; // change species of the targeted ship case KEY_DEBUGGED + KEY_S: { if ( Player_ai->target_objnum < 0 ) break; object *objp; ship_info *sip; objp = &Objects[Player_ai->target_objnum]; if ( objp->type != OBJ_SHIP ) return; sip = &Ship_info[Ships[objp->instance].ship_info_index]; sip->species++; if (sip->species >= Num_species) sip->species = 0; HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Species of target changed to: %s", 24), Species_info[sip->species].species_name); break; } case KEY_DEBUGGED + KEY_SHIFTED + KEY_S: game_increase_skill_level(); HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Skill level set to %s.", 25), Skill_level_names(Game_skill_level)); break; /*// kill all missiles case KEY_DEBUGGED + KEY_SHIFTED + KEY_1: beam_test(1); break; case KEY_DEBUGGED + KEY_SHIFTED + KEY_2: beam_test(2); break; case KEY_DEBUGGED + KEY_SHIFTED + KEY_3: beam_test(3); break; case KEY_DEBUGGED + KEY_SHIFTED + KEY_4: beam_test(4); break; case KEY_DEBUGGED + KEY_SHIFTED + KEY_5: beam_test(5); break; case KEY_DEBUGGED + KEY_SHIFTED + KEY_6: beam_test(6); break; case KEY_DEBUGGED + KEY_SHIFTED + KEY_7: beam_test(7); break; case KEY_DEBUGGED + KEY_SHIFTED + KEY_8: beam_test(8); break; case KEY_DEBUGGED + KEY_SHIFTED + KEY_9: beam_test(9); break; case KEY_DEBUGGED + KEY_CTRLED + KEY_1: beam_test_new(1); break; case KEY_DEBUGGED + KEY_CTRLED + KEY_2: beam_test_new(2); break; case KEY_DEBUGGED + KEY_CTRLED + KEY_3: beam_test_new(3); break;*/ #ifndef NO_SOUND case KEY_DEBUGGED + KEY_T: { char buf[256]; event_music_get_info(buf); HUD_sourced_printf(HUD_SOURCE_HIDDEN, buf); break; } case KEY_DEBUGGED + KEY_UP: case KEY_DEBUGGED1 + KEY_UP: debug_change_song(1); break; case KEY_DEBUGGED + KEY_DOWN: case KEY_DEBUGGED1 + KEY_DOWN: debug_change_song(-1); break; #endif case KEY_PADMINUS: { int init_flag = 0; if ( keyd_pressed[KEY_1] ) { init_flag = 1; HUD_color_red -= 4; } if ( keyd_pressed[KEY_2] ) { init_flag = 1; HUD_color_green -= 4; } if ( keyd_pressed[KEY_3] ) { init_flag = 1; HUD_color_blue -= 4; } if (init_flag) HUD_init_colors(); break; } case KEY_DEBUGGED + KEY_Y: /* // blast a debug lightning bolt in front of the player vec3d start, strike; vm_vec_scale_add(&start, &Player_obj->pos, &Player_obj->orient.fvec, 300.0f); vm_vec_scale_add2(&start, &Player_obj->orient.rvec, -300.0f); vm_vec_scale_add(&strike, &start, &Player_obj->orient.rvec, 600.0f); nebl_bolt(DEBUG_BOLT, &start, &strike); */ extern int tst; tst = 2; break; case KEY_PADPLUS: { int init_flag = 0; if ( keyd_pressed[KEY_1] ) { init_flag = 1; HUD_color_red += 4; } if ( keyd_pressed[KEY_2] ) { init_flag = 1; HUD_color_green += 4; } if ( keyd_pressed[KEY_3] ) { init_flag = 1; HUD_color_blue += 4; } if (init_flag) HUD_init_colors(); break; } case KEY_DEBUGGED + KEY_ALTED + KEY_EQUAL: case KEY_DEBUGGED1 + KEY_ALTED + KEY_EQUAL: { Viewer_zoom += 0.1f; g3_set_view_matrix(&Eye_position, &Eye_matrix, Viewer_zoom); HUD_sourced_printf(HUD_SOURCE_HIDDEN, "viewer zoom raised to %0.2f" , Viewer_zoom); } break; case KEY_DEBUGGED + KEY_ALTED + KEY_MINUS: case KEY_DEBUGGED1 + KEY_ALTED + KEY_MINUS: { Viewer_zoom -= 0.1f; g3_set_view_matrix(&Eye_position, &Eye_matrix, Viewer_zoom); HUD_sourced_printf(HUD_SOURCE_HIDDEN, "viewer zoom lowered to %0.2f" , Viewer_zoom); } break; case KEY_DEBUGGED + KEY_Z: case KEY_DEBUGGED1 + KEY_Z: { Show_cpu = !Show_cpu; } break; } // end switch } //#endif void ppsk_hotkeys(int k) { #ifndef FS2_DEMO // use k to check for keys that can have Shift,Ctrl,Alt,Del status int hotkey_set; #ifndef NDEBUG k &= ~KEY_DEBUGGED; // since hitting F11 will set this bit #endif switch (k) { case KEY_F5: case KEY_F6: case KEY_F7: case KEY_F8: case KEY_F9: case KEY_F10: case KEY_F11: case KEY_F12: hotkey_set = mission_hotkey_get_set_num(k); if ( !(Players[Player_num].flags & PLAYER_FLAGS_MSG_MODE) ) hud_target_hotkey_select( hotkey_set ); else hud_squadmsg_hotkey_select( hotkey_set ); break; case KEY_F5 + KEY_SHIFTED: case KEY_F6 + KEY_SHIFTED: case KEY_F7 + KEY_SHIFTED: case KEY_F8 + KEY_SHIFTED: case KEY_F9 + KEY_SHIFTED: case KEY_F10 + KEY_SHIFTED: case KEY_F11 + KEY_SHIFTED: case KEY_F12 + KEY_SHIFTED: hotkey_set = mission_hotkey_get_set_num(k&(~KEY_SHIFTED)); mprintf(("Adding to set %d\n", hotkey_set+1)); if ( Player_ai->target_objnum == -1) HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "No target to add/remove from set %d.", 26), hotkey_set+1); else { hud_target_hotkey_add_remove( hotkey_set, &Objects[Player_ai->target_objnum], HOTKEY_USER_ADDED); 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); } break; case KEY_F5 + KEY_SHIFTED + KEY_ALTED: case KEY_F6 + KEY_SHIFTED + KEY_ALTED: case KEY_F7 + KEY_SHIFTED + KEY_ALTED: case KEY_F8 + KEY_SHIFTED + KEY_ALTED: case KEY_F9 + KEY_SHIFTED + KEY_ALTED: case KEY_F10 + KEY_SHIFTED + KEY_ALTED: case KEY_F11 + KEY_SHIFTED + KEY_ALTED: case KEY_F12 + KEY_SHIFTED + KEY_ALTED: hotkey_set = mission_hotkey_get_set_num(k & ~KEY_SHIFTED+KEY_ALTED); hud_target_hotkey_clear( hotkey_set ); break; case KEY_SHIFTED + KEY_MINUS: if ( HUD_color_alpha > HUD_COLOR_ALPHA_USER_MIN ) { HUD_color_alpha--; HUD_init_colors(); } break; /* case KEY_SHIFTED + KEY_U: { object *debris_create(object *source_obj, int model_num, int submodel_num, vec3d *pos, vec3d *exp_center, int hull_flag, float exp_force); 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); if (temp) { temp->hull_strength = 5000.0f; int objnum = temp - Objects; vm_vec_copy_scale(&Objects[objnum].phys_info.vel, &Player_obj->orient.fvec, 30.0f); } } break; */ case KEY_SHIFTED + KEY_EQUAL: if ( HUD_color_alpha < HUD_COLOR_ALPHA_USER_MAX ) { HUD_color_alpha++; HUD_init_colors(); } break; } // end switch #endif } // check keypress 'key' against a set of valid controls and mark the match in the // player's button info bitfield. Also checks joystick controls in the set. // // key = scancode (plus modifiers). // count = total size of the list // list = list of Control_config struct action indices to check for void process_set_of_keys(int key, int count, int *list) { int i; for (i=0; ibi, list[i]); } // routine to process keys used for player ship stuff (*not* ship movement). void process_player_ship_keys(int k) { int masked_k; masked_k = k & ~KEY_CTRLED; // take out CTRL modifier only // moved this line to beginning of function since hotkeys now encompass // F5 - F12. We can return after using F11 as a hotkey. ppsk_hotkeys(masked_k); if (keyd_pressed[KEY_DEBUG_KEY]){ return; } // if we're in supernova mode. do nothing if(Player->control_mode == PCM_SUPERNOVA){ return; } // pass the key to the squadmate messaging code. If the messaging code took the key, then return // from here immediately since we don't want to do further key processing. if ( hud_squadmsg_read_key(k) ) return; if ( Player->control_mode == PCM_NORMAL ) { // The following things are not legal to do while dead. if ( !(Game_mode & GM_DEAD) ) { process_set_of_keys(masked_k, Normal_key_set_size, Normal_key_set); } else { process_set_of_keys(masked_k, Dead_key_set_size, Dead_key_set); } } else { } } // Handler for when player hits 'ESC' during the game void game_do_end_mission_popup() { int pf_flags, choice; // char savegame_filename[_MAX_FNAME]; // do the multiplayer version of this if(Game_mode & GM_MULTIPLAYER){ multi_quit_game(PROMPT_ALL); } else { // single player version.... // do housekeeping things. game_stop_time(); #ifndef NO_SOUND game_stop_looped_sounds(); snd_stop_all(); #endif pf_flags = PF_BODY_BIG | PF_USE_AFFIRMATIVE_ICON | PF_USE_NEGATIVE_ICON; 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)); switch (choice) { case 1: // save the game before quitting if in campaign mode // MWA -- 3/26/98 -- no more save/restore!!!! /* if ( Game_mode & GM_CAMPAIGN_MODE ) { memset(savegame_filename, 0, _MAX_FNAME); mission_campaign_savefile_generate_root(savegame_filename); strcat(savegame_filename, NOX("svg")); if ( state_save_all(savegame_filename) ) { Int3(); // could not save this game } } */ gameseq_post_event(GS_EVENT_END_GAME); break; case 2: gameseq_post_event(GS_EVENT_ENTER_GAME); break; default: break; // do nothing } game_start_time(); game_flush(); } } // handle pause keypress void game_process_pause_key() { // special processing for multiplayer if (Game_mode & GM_MULTIPLAYER) { if(Multi_pause_status){ multi_pause_request(0); } else { multi_pause_request(1); } } else { gameseq_post_event( GS_EVENT_PAUSE_GAME ); } } #define WITHIN_BBOX() do { \ float scale = 2.0f; \ polymodel *pm = model_get(s_check->modelnum); \ collided = 0; \ if(pm != NULL){ \ vec3d temp = new_obj->pos; \ vec3d gpos; \ vm_vec_sub2(&temp, &hit_check->pos); \ vm_vec_rotate(&gpos, &temp, &hit_check->orient); \ if((gpos.xyz.x >= pm->mins.xyz.x * scale) && (gpos.xyz.y >= pm->mins.xyz.y * scale) && (gpos.xyz.z >= pm->mins.xyz.z * scale) && (gpos.xyz.x <= pm->maxs.xyz.x * scale) && (gpos.xyz.y <= pm->maxs.xyz.y * scale) && (gpos.xyz.z <= pm->maxs.xyz.z * scale)) { \ collided = 1; \ } \ } \ } while(0) #define MOVE_AWAY_BBOX() do { \ polymodel *pm = model_get(s_check->modelnum); \ if(pm != NULL){ \ switch((int)frand_range(0.0f, 3.9f)){ \ case 0: \ new_obj->pos.xyz.x += 200.0f; \ break; \ case 1: \ new_obj->pos.xyz.x -= 200.0f; \ break; \ case 2: \ new_obj->pos.xyz.y += 200.0f; \ break; \ case 3: \ new_obj->pos.xyz.y -= 200.0f; \ break; \ default : \ new_obj->pos.xyz.z -= 200.0f; \ break; \ } \ } \ } while(0) // process cheat codes void game_process_cheats(int k) { int i; char *cryptstring; if ( k == 0 ){ return; } // no cheats in multiplayer, ever if(Game_mode & GM_MULTIPLAYER){ Cheats_enabled = 0; return; } k = key_to_ascii(k); for (i = 0; i < CHEAT_BUFFER_LEN; i++){ CheatBuffer[i]=CheatBuffer[i+1]; } CheatBuffer[CHEATSPOT]=(char)k; cryptstring=jcrypt(&CheatBuffer[CHEAT_BUFFER_LEN - CRYPT_STRING_LENGTH]); #ifdef FS2_DEMO if ( !strcmp(Cheat_code_demo, cryptstring) ) { HUD_printf(XSTR( "Cheats enabled.", 31)); Cheats_enabled = 1; if (Player->flags & PLAYER_FLAGS_MSG_MODE){ hud_squadmsg_toggle(); } } #else if( !strcmp(Cheat_code, cryptstring) && !(Game_mode & GM_MULTIPLAYER)){ Cheats_enabled = 1; // cheating allows the changing of weapons so we have to grab anything // that we don't already have loaded, just in case extern void weapons_page_in_cheats(); weapons_page_in_cheats(); HUD_printf("Cheats enabled"); } if( !strcmp(Cheat_code_fish, cryptstring) ){ // only enable in the main hall if((gameseq_get_state() == GS_STATE_MAIN_MENU) && (main_hall_id() == 1)){ extern void fishtank_start(); fishtank_start(); } } if( !strcmp(Cheat_code_headz, cryptstring) ){ main_hall_vasudan_funny(); } if( !strcmp(Cheat_code_skip, cryptstring) && (gameseq_get_state() == GS_STATE_MAIN_MENU)){ extern void main_hall_campaign_cheat(); main_hall_campaign_cheat(); } if( !strcmp(Cheat_code_tooled, cryptstring) && (Game_mode & GM_IN_MISSION)){ Tool_enabled = 1; HUD_printf("Prepare to be taken to school"); } if( !strcmp(Cheat_code_pirate, cryptstring) && (Game_mode & GM_IN_MISSION) && (Player_obj != NULL)){ HUD_printf(NOX("Walk the plank")); for(int idx=0; idx<1; idx++){ vec3d add = Player_obj->pos; add.xyz.x += frand_range(-700.0f, 700.0f); add.xyz.y += frand_range(-700.0f, 700.0f); add.xyz.z += frand_range(-700.0f, 700.0f); int objnum = ship_create(&vmd_identity_matrix, &add, Num_ship_classes - 1); if(objnum >= 0){ int collided; ship_obj *moveup; object *hit_check; ship *s_check; object *new_obj = &Objects[objnum]; // place him // now make sure we're not colliding with anyone do { collided = 0; moveup = GET_FIRST(&Ship_obj_list); while(moveup!=END_OF_LIST(&Ship_obj_list)){ // don't check the new_obj itself!! if(moveup->objnum != objnum){ hit_check = &Objects[moveup->objnum]; Assert(hit_check->type == OBJ_SHIP); Assert(hit_check->instance >= 0); if((hit_check->type != OBJ_SHIP) || (hit_check->instance < 0)){ continue; } s_check = &Ships[hit_check->instance]; // just to make sure we don't get any strange magnitude errors if(vm_vec_same(&hit_check->pos, &Objects[objnum].pos)){ Objects[objnum].pos.xyz.x += 1.0f; } WITHIN_BBOX(); if(collided){ MOVE_AWAY_BBOX(); break; } collided = 0; } moveup = GET_NEXT(moveup); } } while(collided); // warpin shipfx_warpin_start(&Objects[objnum]); // tell him to attack // ai_add_ship_goal_player( AIG_TYPE_PLAYER_SHIP, AI_GOAL_CHASE_ANY, SM_ATTACK, NULL, &Ai_info[Ships[Objects[objnum].instance].ai_index] ); } } } #endif /* //#ifdef INTERPLAYQA if ( !strcmp(Cheat_code_in_game, cryptstring) ) { HUD_printf(XSTR( "Cheats enabled.", 31)); Cheats_enabled = 1; if (Player->flags & PLAYER_FLAGS_MSG_MODE){ hud_squadmsg_toggle(); } } else if ( !strcmp(Cheat_code_movies, cryptstring) ) { HUD_printf(XSTR( "All movies available in Tech Room", 32)); All_movies_enabled = 1; if (Player->flags & PLAYER_FLAGS_MSG_MODE){ hud_squadmsg_toggle(); } } else if( !strcmp(Cheat_code_pirate, cryptstring) ){ HUD_printf(NOX("Walk the plank")); for(int idx=0; idx<1; idx++){ vec3d add; add.xyz.x = frand_range(-1000.0f, 1000.0f); add.xyz.y = frand_range(-1000.0f, 1000.0f); add.xyz.z = frand_range(-1000.0f, 1000.0f); int objnum = ship_create(&vmd_identity_matrix, &add, Num_ship_classes - 1); if(objnum >= 0){ shipfx_warpin_start(&Objects[objnum]); } } } #endif */ } void game_process_keys() { int k; button_info_clear(&Player->bi); // clear out the button info struct for the player do { k = game_poll(); //if (k) // mprintf(("got key %d at %s:%d\n", k, __FILE__, __LINE__)); // AL 12-10-97: Scan for keys used to leave the dead state (don't process any) // DB 1-13-98 : New popup code will run the game do state, so we must skip // all key processing in this function, since everything should be run through the popup dialog if ( Game_mode & GM_DEAD_BLEW_UP ) { continue; } game_process_cheats( k ); // mwa -- 4/5/97 Moved these two function calls before the switch statement. I don't think // that this has adverse affect on anything and is acutally desireable because of the // ESC key being used to quit any HUD message/input mode that might be currently in use process_player_ship_keys(k); // #ifndef NDEBUG process_debug_keys(k); // Note, also processed for cheats. // #endif switch (k) { case 0: // No key break; case KEY_ESC: if ( Player->control_mode != PCM_NORMAL ) { if ( Player->control_mode == PCM_WARPOUT_STAGE1 ) { gameseq_post_event( GS_EVENT_PLAYER_WARPOUT_STOP ); } else { // too late to abort warp out! } } else { // let the ESC key break out of messaging mode if ( Players[Player_num].flags & PLAYER_FLAGS_MSG_MODE ) { hud_squadmsg_toggle(); break; } //If topdown view in non-2D mission, go back to cockpit view. if ( (Viewer_mode & VM_TOPDOWN) && !(The_mission.flags & MISSION_FLAG_2D_MISSION)) { Viewer_mode &= ~VM_TOPDOWN; break; } // if in external view or chase view, go back to cockpit view if ( Viewer_mode & (VM_EXTERNAL|VM_CHASE|VM_OTHER_SHIP) ) { Viewer_mode &= ~(VM_EXTERNAL|VM_CHASE|VM_OTHER_SHIP); break; } if (!(Game_mode & GM_DEAD_DIED)) game_do_end_mission_popup(); } break; case KEY_Y: break; case KEY_N: break; case KEY_ALTED + KEY_SHIFTED+KEY_J: // treat the current joystick position as the center position joy_set_cen(); break; case KEY_DEBUGGED | KEY_PAUSE: gameseq_post_event( GS_EVENT_DEBUG_PAUSE_GAME ); break; case KEY_ALTED + KEY_PAUSE: if( Game_mode & GM_DEAD_BLEW_UP || Game_mode & GM_DEAD_DIED) { break; } pause_set_type(PAUSE_TYPE_VIEWER); game_process_pause_key(); break; case KEY_PAUSE: if( Game_mode & GM_DEAD_BLEW_UP || Game_mode & GM_DEAD_DIED) { break; } pause_set_type(PAUSE_TYPE_NORMAL); game_process_pause_key(); break; } // end switch } while (k); button_info_do(&Player->bi); // call functions based on status of button_info bit vectors } int button_function_critical(int n, net_player *p = NULL) { object *objp; player *pl; net_player *npl; int at_self; // flag indicating the object is local (for hud messages, etc) Assert(n >= 0); // multiplayer clients should leave critical button bits alone and pass them to the server instead if ((Game_mode & GM_MULTIPLAYER) && !(Net_player->flags & NETINFO_FLAG_AM_MASTER)) { // if this flag is set, we should apply the button itself (came from the server) if (!Multi_button_info_ok){ return 0; } } // in single player mode make sure we're using the player object and the player himself, otherwise use the object and // player pertaining to the passed net_player npl = NULL; if (p == NULL) { objp = Player_obj; pl = Player; if(Game_mode & GM_MULTIPLAYER){ npl = Net_player; // if we're the server in multiplayer and we're an observer, don't process our own critical button functions if((Net_player->flags & NETINFO_FLAG_AM_MASTER) && (Net_player->flags & NETINFO_FLAG_OBSERVER)){ return 0; } } at_self = 1; } else { objp = &Objects[p->m_player->objnum]; pl = p->m_player; npl = p; at_self = 0; if ( NETPLAYER_IS_DEAD(npl) || (Ships[Objects[pl->objnum].instance].flags & SF_DYING) ) return 0; } switch (n) { // cycle to next secondary weapon case CYCLE_SECONDARY: if(at_self) control_used(CYCLE_SECONDARY); hud_gauge_popup_start(HUD_WEAPONS_GAUGE); if (ship_select_next_secondary(objp)) { ship* shipp = &Ships[objp->instance]; if ( timestamp_elapsed(shipp->weapons.next_secondary_fire_stamp[shipp->weapons.current_secondary_bank]) ) { shipp->weapons.next_secondary_fire_stamp[shipp->weapons.current_secondary_bank] = timestamp(250); // 1/4 second delay until can fire } // multiplayer server should maintain bank/link status here if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){ Assert(npl != NULL); multi_server_update_player_weapons(npl,shipp); } } break; // cycle number of missiles case CYCLE_NUM_MISSLES: if(at_self) control_used(CYCLE_NUM_MISSLES); if ( objp == Player_obj ) { if ( Player_ship->weapons.num_secondary_banks <= 0 ) { HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "This ship has no secondary weapons", 33)); gamesnd_play_iface(SND_GENERAL_FAIL); break; } } if ( Ships[objp->instance].flags & SF_SECONDARY_DUAL_FIRE ) { Ships[objp->instance].flags &= ~SF_SECONDARY_DUAL_FIRE; if(at_self) { HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Secondary weapon set to normal fire mode", 34)); snd_play( &Snds[SND_SECONDARY_CYCLE] ); hud_gauge_popup_start(HUD_WEAPONS_GAUGE); } } else { Ships[objp->instance].flags |= SF_SECONDARY_DUAL_FIRE; if(at_self) { HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Secondary weapon set to dual fire mode", 35)); snd_play( &Snds[SND_SECONDARY_CYCLE] ); hud_gauge_popup_start(HUD_WEAPONS_GAUGE); } } // multiplayer server should maintain bank/link status here if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){ Assert(npl != NULL); multi_server_update_player_weapons(npl,&Ships[objp->instance]); } break; // increase weapon recharge rate case INCREASE_WEAPON: if(at_self) control_used(INCREASE_WEAPON); increase_recharge_rate(objp, WEAPONS); // multiplayer server should maintain bank/link status here if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){ Assert(npl != NULL); multi_server_update_player_weapons(npl,&Ships[objp->instance]); } break; // decrease weapon recharge rate case DECREASE_WEAPON: if(at_self) control_used(DECREASE_WEAPON); decrease_recharge_rate(objp, WEAPONS); // multiplayer server should maintain bank/link status here if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){ Assert(npl != NULL); multi_server_update_player_weapons(npl,&Ships[objp->instance]); } break; // increase shield recharge rate case INCREASE_SHIELD: if(at_self) control_used(INCREASE_SHIELD); increase_recharge_rate(objp, SHIELDS); // multiplayer server should maintain bank/link status here if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){ Assert(npl != NULL); multi_server_update_player_weapons(npl,&Ships[objp->instance]); } break; // decrease shield recharge rate case DECREASE_SHIELD: if(at_self) control_used(DECREASE_SHIELD); decrease_recharge_rate(objp, SHIELDS); // multiplayer server should maintain bank/link status here if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){ Assert(npl != NULL); multi_server_update_player_weapons(npl,&Ships[objp->instance]); } break; // increase energy to engines case INCREASE_ENGINE: if(at_self) control_used(INCREASE_ENGINE); increase_recharge_rate(objp, ENGINES); // multiplayer server should maintain bank/link status here if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){ Assert(npl != NULL); multi_server_update_player_weapons(npl,&Ships[objp->instance]); } break; // decrease energy to engines case DECREASE_ENGINE: if(at_self) control_used(DECREASE_ENGINE); decrease_recharge_rate(objp, ENGINES); // multiplayer server should maintain bank/link status here if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){ Assert(npl != NULL); multi_server_update_player_weapons(npl,&Ships[objp->instance]); } break; // equalize recharge rates case ETS_EQUALIZE: if (at_self) { control_used(ETS_EQUALIZE); } set_default_recharge_rates(objp); snd_play( &Snds[SND_ENERGY_TRANS] ); // multiplayer server should maintain bank/link status here if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){ Assert(npl != NULL); multi_server_update_player_weapons(npl,&Ships[objp->instance]); } break; // equalize shield energy to all quadrants case SHIELD_EQUALIZE: if(at_self){ control_used(SHIELD_EQUALIZE); } hud_shield_equalize(objp, pl); break; // transfer shield energy to front case SHIELD_XFER_TOP: if(at_self){ control_used(SHIELD_XFER_TOP); } hud_augment_shield_quadrant(objp, 1); break; // transfer shield energy to rear case SHIELD_XFER_BOTTOM: if(at_self) control_used(SHIELD_XFER_BOTTOM); hud_augment_shield_quadrant(objp, 2); break; // transfer shield energy to left case SHIELD_XFER_LEFT: if(at_self) control_used(SHIELD_XFER_LEFT); hud_augment_shield_quadrant(objp, 3); break; // transfer shield energy to right case SHIELD_XFER_RIGHT: if(at_self) control_used(SHIELD_XFER_RIGHT); hud_augment_shield_quadrant(objp, 0); break; // transfer energy to shield from weapons case XFER_SHIELD: if(at_self) control_used(XFER_SHIELD); transfer_energy_to_shields(objp); break; // transfer energy to weapons from shield case XFER_LASER: if(at_self) control_used(XFER_LASER); transfer_energy_to_weapons(objp); break; // following are not handled here, but we need to bypass the Int3() case LAUNCH_COUNTERMEASURE: case VIEW_SLEW: case VIEW_EXTERNAL: case VIEW_EXTERNAL_TOGGLE_CAMERA_LOCK: case VIEW_TRACK_TARGET: case ONE_THIRD_THROTTLE: case TWO_THIRDS_THROTTLE: case MINUS_5_PERCENT_THROTTLE: case PLUS_5_PERCENT_THROTTLE: case ZERO_THROTTLE: case MAX_THROTTLE: return 0; default : Int3(); // bad bad bad break; } return 1; } // return !0 if the action is allowed, otherwise return 0 int button_allowed(int n) { // RT Commented this out cos it was disabling use of keys when HUD is off #if 0 if ( hud_disabled() ) { switch (n) { case SHOW_GOALS: case END_MISSION: case CYCLE_NEXT_PRIMARY: case CYCLE_PREV_PRIMARY: case CYCLE_SECONDARY: case ONE_THIRD_THROTTLE: case TWO_THIRDS_THROTTLE: case PLUS_5_PERCENT_THROTTLE: case MINUS_5_PERCENT_THROTTLE: case ZERO_THROTTLE: case MAX_THROTTLE: return 1; default: return 0; } } #endif return 1; } // execute function corresponding to action n // basically, these are actions which don't affect demo playback at all int button_function_demo_valid(int n) { // 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 // playback. int ret = 0; // No keys, not even targeting keys, when player in death roll. He can press keys after he blows up. if (Game_mode & GM_DEAD_DIED){ return 0; } // any of these buttons are valid switch(n){ case VIEW_CHASE: control_used(VIEW_CHASE); if(!Perspective_locked) { Viewer_mode ^= VM_CHASE; if ( Viewer_mode & VM_CHASE ) { Viewer_mode &= ~VM_EXTERNAL; } } else { snd_play( &Snds[SND_TARGET_FAIL] ); } ret = 1; break; case VIEW_EXTERNAL: control_used(VIEW_EXTERNAL); if(!Perspective_locked) { Viewer_mode ^= VM_EXTERNAL; Viewer_mode &= ~VM_EXTERNAL_CAMERA_LOCKED; // reset camera lock when leave/entering external view if ( Viewer_mode & VM_EXTERNAL ) { Viewer_mode &= ~VM_CHASE; } } else { snd_play( &Snds[SND_TARGET_FAIL] ); } ret = 1; break; case VIEW_TOPDOWN: control_used(VIEW_TOPDOWN); if(!Perspective_locked) { Viewer_mode ^= VM_TOPDOWN; } else { snd_play( &Snds[SND_TARGET_FAIL] ); } ret = 1; break; case VIEW_EXTERNAL_TOGGLE_CAMERA_LOCK: control_used(VIEW_EXTERNAL_TOGGLE_CAMERA_LOCK); if ( Viewer_mode & VM_EXTERNAL ) { Viewer_mode ^= VM_EXTERNAL_CAMERA_LOCKED; if ( Viewer_mode & VM_EXTERNAL_CAMERA_LOCKED ) { HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "External camera is locked, controls will move ship", 36)); } else { HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "External camera is free, controls will move the camera, not the ship", 37)); } } ret = 1; break; case VIEW_OTHER_SHIP: control_used(VIEW_OTHER_SHIP); if ( Player_ai->target_objnum < 0 || Perspective_locked) { snd_play( &Snds[SND_TARGET_FAIL] ); } else { if ( Objects[Player_ai->target_objnum].type != OBJ_SHIP ) { snd_play( &Snds[SND_TARGET_FAIL] ); } else { Viewer_mode ^= VM_OTHER_SHIP; } } ret = 1; break; case TIME_SLOW_DOWN: if ( Game_mode & GM_NORMAL ) { // Goober5000 - time dilation only available in cheat mode (see above); // now you can do it with or without pressing the tilde, per Kazan's request if ( ((Game_time_compression > F1_0) || (Cheats_enabled && (Game_time_compression > (F1_0/MAX_TIME_DIVIDER)))) && !Time_compression_locked) { change_time_compression(0.5f); } else { gamesnd_play_error_beep(); } } else { gamesnd_play_error_beep(); } ret = 1; break; case TIME_SPEED_UP: if ( Game_mode & GM_NORMAL ) { if ( (Game_time_compression < (F1_0*MAX_TIME_MULTIPLIER)) && !Time_compression_locked ) { change_time_compression(2.0f); } else { gamesnd_play_error_beep(); } } else { gamesnd_play_error_beep(); } ret = 1; break; } // done return ret; } // execute function corresponding to action n (BUTTON_ #define from KeyControl.h) // Goober5000: function returns 1 when action was taken int button_function(int n) { Assert(n >= 0); //mprintf(("got button %d at %s:%d\n", n, __FILE__, __LINE__)); if ( !button_allowed(n) ) { return 0; } // No keys, not even targeting keys, when player in death roll. He can press keys after he blows up. if (Game_mode & GM_DEAD_DIED){ return 0; } // Goober5000 - if the ship doesn't have subspace drive, jump key doesn't work: so test and exit early if (Player_ship->flags2 & SF2_NO_SUBSPACE_DRIVE) { switch(n) { case END_MISSION: control_used(n); // set the timestamp for when we used the control, in case we need it return 1; // pretend we took the action: if we return 0, strange stuff may happen } } // Goober5000 - if we have primitive sensors, some keys don't work: so test and exit early if (Player_ship->flags2 & SF2_PRIMITIVE_SENSORS) { switch (n) { case MATCH_TARGET_SPEED: case TOGGLE_AUTO_MATCH_TARGET_SPEED: case TOGGLE_AUTO_TARGETING: case TARGET_NEXT: case TARGET_PREV: case TARGET_NEXT_CLOSEST_HOSTILE: case TARGET_PREV_CLOSEST_HOSTILE: case TARGET_NEXT_CLOSEST_FRIENDLY: case TARGET_PREV_CLOSEST_FRIENDLY: case TARGET_SHIP_IN_RETICLE: case TARGET_LAST_TRANMISSION_SENDER: case TARGET_CLOSEST_REPAIR_SHIP: case TARGET_CLOSEST_SHIP_ATTACKING_TARGET: case STOP_TARGETING_SHIP: case TARGET_CLOSEST_SHIP_ATTACKING_SELF: case TARGET_TARGETS_TARGET: case TARGET_SUBOBJECT_IN_RETICLE: case TARGET_NEXT_SUBOBJECT: case TARGET_PREV_SUBOBJECT: case STOP_TARGETING_SUBSYSTEM: case TARGET_NEXT_BOMB: case TARGET_PREV_BOMB: case TARGET_NEXT_UNINSPECTED_CARGO: case TARGET_PREV_UNINSPECTED_CARGO: case TARGET_NEWEST_SHIP: case TARGET_NEXT_LIVE_TURRET: case TARGET_PREV_LIVE_TURRET: case TARGET_NEXT_ESCORT_SHIP: control_used(n); // set the timestamp for when we used the control, in case we need it return 1; // pretend we took the action: if we return 0, strange stuff may happen } } // now handle keys the regular way switch (n) { // cycle to next primary weapon case CYCLE_NEXT_PRIMARY: // bogus? if((Player_obj == NULL) || (Player_ship == NULL)){ break; } hud_gauge_popup_start(HUD_WEAPONS_GAUGE); if (ship_select_next_primary(Player_obj, CYCLE_PRIMARY_NEXT)) { ship* shipp = Player_ship; shipp->weapons.next_primary_fire_stamp[shipp->weapons.current_primary_bank] = timestamp(250); // 1/4 second delay until can fire // multiplayer server should maintain bank/link status here // if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){ // Assert(npl != NULL); // multi_server_update_player_weapons(npl,shipp); // } } break; // cycle to previous primary weapon case CYCLE_PREV_PRIMARY: // bogus? if((Player_obj == NULL) || (Player_ship == NULL)){ break; } hud_gauge_popup_start(HUD_WEAPONS_GAUGE); if (ship_select_next_primary(Player_obj, CYCLE_PRIMARY_PREV)) { ship* shipp = Player_ship; shipp->weapons.next_primary_fire_stamp[shipp->weapons.current_primary_bank] = timestamp(250); // 1/4 second delay until can fire // multiplayer server should maintain bank/link status here // if((Game_mode & GM_MULTIPLAYER) && (Net_player->flags & NETINFO_FLAG_AM_MASTER)){ // Assert(npl != NULL); // multi_server_update_player_weapons(npl,shipp); // } } break; // cycle to next secondary weapon case CYCLE_SECONDARY: return button_function_critical(CYCLE_SECONDARY); break; // cycle number of missiles fired from secondary bank case CYCLE_NUM_MISSLES: return button_function_critical(CYCLE_NUM_MISSLES); break; // undefined in multiplayer for clients right now // match target speed case MATCH_TARGET_SPEED: control_used(MATCH_TARGET_SPEED); // If player is auto-matching, break auto-match speed if ( Player->flags & PLAYER_FLAGS_AUTO_MATCH_SPEED ) { Player->flags &= ~PLAYER_FLAGS_AUTO_MATCH_SPEED; } player_match_target_speed(); break; // undefined in multiplayer for clients right now // toggle auto-match target speed case TOGGLE_AUTO_MATCH_TARGET_SPEED: // multiplayer observers can't match target speed if((Game_mode & GM_MULTIPLAYER) && (Net_player != NULL) && ((Net_player->flags & NETINFO_FLAG_OBSERVER) || (Player_obj->type == OBJ_OBSERVER)) ){ break; } Player->flags ^= PLAYER_FLAGS_AUTO_MATCH_SPEED; control_used(TOGGLE_AUTO_MATCH_TARGET_SPEED); hud_gauge_popup_start(HUD_AUTO_SPEED); if ( Players[Player_num].flags & PLAYER_FLAGS_AUTO_MATCH_SPEED ) { snd_play(&Snds[SND_SHIELD_XFER_OK], 1.0f); // HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Auto match target speed activated", -1)); if ( !Player->flags & PLAYER_FLAGS_MATCH_TARGET ) { player_match_target_speed(); } } else { // HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Auto match target deactivated", -1)); snd_play(&Snds[SND_SHIELD_XFER_OK], 1.0f); player_match_target_speed(); } break; // target next case TARGET_NEXT: control_used(TARGET_NEXT); if ( hud_sensors_ok(Player_ship) ) { hud_target_next(); } break; // target previous case TARGET_PREV: control_used(TARGET_PREV); if ( hud_sensors_ok(Player_ship) ) { hud_target_prev(); } break; // target the next hostile target case TARGET_NEXT_CLOSEST_HOSTILE: control_used(TARGET_NEXT_CLOSEST_HOSTILE); if (hud_sensors_ok(Player_ship)){ hud_target_next_list(); } break; // target the previous closest hostile case TARGET_PREV_CLOSEST_HOSTILE: control_used(TARGET_PREV_CLOSEST_HOSTILE); if (hud_sensors_ok(Player_ship)){ hud_target_next_list(1,0); } break; // toggle auto-targeting case TOGGLE_AUTO_TARGETING: control_used(TOGGLE_AUTO_TARGETING); hud_gauge_popup_start(HUD_AUTO_TARGET); Players[Player_num].flags ^= PLAYER_FLAGS_AUTO_TARGETING; if ( Players[Player_num].flags & PLAYER_FLAGS_AUTO_TARGETING ) { if (hud_sensors_ok(Player_ship)) { hud_target_closest(iff_get_attackee_mask(Player_ship->team), -1, FALSE, TRUE ); snd_play(&Snds[SND_SHIELD_XFER_OK], 1.0f); // HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Auto targeting activated", -1)); } else { Players[Player_num].flags ^= PLAYER_FLAGS_AUTO_TARGETING; } } else { snd_play(&Snds[SND_SHIELD_XFER_OK], 1.0f); // HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Auto targeting deactivated", -1)); } break; // target the next friendly ship case TARGET_NEXT_CLOSEST_FRIENDLY: control_used(TARGET_NEXT_CLOSEST_FRIENDLY); if (hud_sensors_ok(Player_ship)){ hud_target_next_list(0); } break; // target the closest friendly ship case TARGET_PREV_CLOSEST_FRIENDLY: control_used(TARGET_PREV_CLOSEST_FRIENDLY); if (hud_sensors_ok(Player_ship)) { hud_target_next_list(0,0); } break; // target ship closest to center of reticle case TARGET_SHIP_IN_RETICLE: control_used(TARGET_SHIP_IN_RETICLE); if (hud_sensors_ok(Player_ship)){ hud_target_in_reticle_new(); } break; case TARGET_LAST_TRANMISSION_SENDER: control_used(TARGET_LAST_TRANMISSION_SENDER); if ( hud_sensors_ok(Player_ship)) { hud_target_last_transmit(); } break; // target the closest repair ship case TARGET_CLOSEST_REPAIR_SHIP: control_used(TARGET_CLOSEST_REPAIR_SHIP); // AL: Try to find the closest repair ship coming to repair the player... if no support // ships are coming to rearm the player, just try for the closest repair ship if ( hud_target_closest_repair_ship(OBJ_INDEX(Player_obj)) == 0 ) { if ( hud_target_closest_repair_ship() == 0 ) { snd_play(&Snds[SND_TARGET_FAIL]); } } break; // target the closest ship attacking current target case TARGET_CLOSEST_SHIP_ATTACKING_TARGET: control_used(TARGET_CLOSEST_SHIP_ATTACKING_TARGET); if (hud_sensors_ok(Player_ship)){ Assert(Player_ai->target_objnum >= 0); hud_target_closest(iff_get_attacker_mask(obj_team(&Objects[Player_ai->target_objnum])), Player_ai->target_objnum); } break; // stop targeting ship case STOP_TARGETING_SHIP: control_used(STOP_TARGETING_SHIP); hud_cease_targeting(); break; // target closest ship that is attacking player case TARGET_CLOSEST_SHIP_ATTACKING_SELF: control_used(TARGET_CLOSEST_SHIP_ATTACKING_SELF); if (hud_sensors_ok(Player_ship)){ hud_target_closest(iff_get_attacker_mask(Player_ship->team), OBJ_INDEX(Player_obj), TRUE, 0, 1); } break; // target your target's target case TARGET_TARGETS_TARGET: control_used(TARGET_TARGETS_TARGET); if (hud_sensors_ok(Player_ship)){ hud_target_targets_target(); } break; // target ships subsystem in reticle case TARGET_SUBOBJECT_IN_RETICLE: control_used(TARGET_SUBOBJECT_IN_RETICLE); if (hud_sensors_ok(Player_ship)){ hud_target_subsystem_in_reticle(); } break; case TARGET_PREV_SUBOBJECT: control_used(TARGET_PREV_SUBOBJECT); if (hud_sensors_ok(Player_ship)){ hud_target_prev_subobject(); } break; // target next subsystem on current target case TARGET_NEXT_SUBOBJECT: control_used(TARGET_NEXT_SUBOBJECT); if (hud_sensors_ok(Player_ship)){ hud_target_next_subobject(); } break; // stop targeting subsystems on ship case STOP_TARGETING_SUBSYSTEM: control_used(STOP_TARGETING_SUBSYSTEM); hud_cease_subsystem_targeting(); break; case TARGET_NEXT_BOMB: control_used(TARGET_NEXT_BOMB); hud_target_missile(Player_obj, 1); break; case TARGET_PREV_BOMB: control_used(TARGET_PREV_BOMB); hud_target_missile(Player_obj, 0); break; case TARGET_NEXT_UNINSPECTED_CARGO: hud_target_uninspected_object(1); break; case TARGET_PREV_UNINSPECTED_CARGO: hud_target_uninspected_object(0); break; case TARGET_NEWEST_SHIP: hud_target_newest_ship(); break; case TARGET_NEXT_LIVE_TURRET: hud_target_live_turret(1); break; case TARGET_PREV_LIVE_TURRET: hud_target_live_turret(0); break; // wingman message: attack current target case ATTACK_MESSAGE: control_used(ATTACK_MESSAGE); hud_squadmsg_shortcut( ATTACK_TARGET_ITEM ); break; // wingman message: disarm current target case DISARM_MESSAGE: control_used(DISARM_MESSAGE); hud_squadmsg_shortcut( DISARM_TARGET_ITEM ); break; // wingman message: disable current target case DISABLE_MESSAGE: control_used(DISABLE_MESSAGE); hud_squadmsg_shortcut( DISABLE_TARGET_ITEM ); break; // wingman message: disable current target case ATTACK_SUBSYSTEM_MESSAGE: control_used(ATTACK_SUBSYSTEM_MESSAGE); hud_squadmsg_shortcut( DISABLE_SUBSYSTEM_ITEM ); break; // wingman message: capture current target case CAPTURE_MESSAGE: control_used(CAPTURE_MESSAGE); hud_squadmsg_shortcut( CAPTURE_TARGET_ITEM ); break; // wingman message: engage enemy case ENGAGE_MESSAGE: control_used(ENGAGE_MESSAGE); hud_squadmsg_shortcut( ENGAGE_ENEMY_ITEM ); break; // wingman message: form on my wing case FORM_MESSAGE: control_used(FORM_MESSAGE); hud_squadmsg_shortcut( FORMATION_ITEM ); break; // wingman message: protect current target case PROTECT_MESSAGE: control_used(PROTECT_MESSAGE); hud_squadmsg_shortcut( PROTECT_TARGET_ITEM ); break; // wingman message: cover me case COVER_MESSAGE: control_used(COVER_MESSAGE); hud_squadmsg_shortcut( COVER_ME_ITEM ); break; // wingman message: warp out case WARP_MESSAGE: control_used(WARP_MESSAGE); hud_squadmsg_shortcut( DEPART_ITEM ); break; case IGNORE_MESSAGE: control_used(IGNORE_MESSAGE); hud_squadmsg_shortcut( IGNORE_TARGET_ITEM ); break; // rearm message case REARM_MESSAGE: control_used(REARM_MESSAGE); hud_squadmsg_rearm_shortcut(); break; // cycle to next radar range case RADAR_RANGE_CYCLE: control_used(RADAR_RANGE_CYCLE); HUD_config.rp_dist++; if ( HUD_config.rp_dist >= RR_MAX_RANGES ) HUD_config.rp_dist = 0; HUD_sourced_printf(HUD_SOURCE_HIDDEN, XSTR( "Radar range set to %s", 38), Radar_range_text(HUD_config.rp_dist)); break; // toggle the squadmate messaging menu case SQUADMSG_MENU: control_used(SQUADMSG_MENU); hud_squadmsg_toggle(); // leave the details to the messaging code!!! break; // show the mission goals screen case SHOW_GOALS: control_used(SHOW_GOALS); gameseq_post_event( GS_EVENT_SHOW_GOALS ); break; // end the mission case END_MISSION: // in multiplayer, all end mission requests should go through the server if(Game_mode & GM_MULTIPLAYER){ multi_handle_end_mission_request(); break; } control_used(END_MISSION); if (collide_predict_large_ship(Player_obj, 200.0f)) { gamesnd_play_iface(SND_GENERAL_FAIL); HUD_printf(XSTR( "** WARNING ** Collision danger. Subspace drive not activated.", 39)); } else if (!ship_engine_ok_to_warp(Player_ship)) { gamesnd_play_iface(SND_GENERAL_FAIL); HUD_printf(XSTR("Engine failure. Cannot engage subspace drive.", 40)); } else if (!ship_navigation_ok_to_warp(Player_ship)) { gamesnd_play_iface(SND_GENERAL_FAIL); HUD_printf(XSTR("Navigation failure. Cannot engage subspace drive.", -1)); } else { gameseq_post_event( GS_EVENT_PLAYER_WARPOUT_START ); } break; case ADD_REMOVE_ESCORT: if ( Player_ai->target_objnum >= 0 ) { control_used(ADD_REMOVE_ESCORT); hud_add_remove_ship_escort(Player_ai->target_objnum); } break; case ESCORT_CLEAR: control_used(ESCORT_CLEAR); hud_escort_clear_all(); break; case TARGET_NEXT_ESCORT_SHIP: control_used(TARGET_NEXT_ESCORT_SHIP); hud_escort_target_next(); break; // increase weapon recharge rate case INCREASE_WEAPON: hud_gauge_popup_start(HUD_ETS_GAUGE); return button_function_critical(INCREASE_WEAPON); break; // decrease weapon recharge rate case DECREASE_WEAPON: hud_gauge_popup_start(HUD_ETS_GAUGE); return button_function_critical(DECREASE_WEAPON); break; // increase shield recharge rate case INCREASE_SHIELD: hud_gauge_popup_start(HUD_ETS_GAUGE); return button_function_critical(INCREASE_SHIELD); break; // decrease shield recharge rate case DECREASE_SHIELD: hud_gauge_popup_start(HUD_ETS_GAUGE); return button_function_critical(DECREASE_SHIELD); break; // increase energy to engines case INCREASE_ENGINE: hud_gauge_popup_start(HUD_ETS_GAUGE); return button_function_critical(INCREASE_ENGINE); break; // decrease energy to engines case DECREASE_ENGINE: hud_gauge_popup_start(HUD_ETS_GAUGE); return button_function_critical(DECREASE_ENGINE); break; case ETS_EQUALIZE: hud_gauge_popup_start(HUD_ETS_GAUGE); return button_function_critical(ETS_EQUALIZE); break; // equalize shield energy to all quadrants case SHIELD_EQUALIZE: return button_function_critical(SHIELD_EQUALIZE); break; // transfer shield energy to front case SHIELD_XFER_TOP: return button_function_critical(SHIELD_XFER_TOP); break; // transfer shield energy to rear case SHIELD_XFER_BOTTOM: return button_function_critical(SHIELD_XFER_BOTTOM); break; // transfer shield energy to left case SHIELD_XFER_LEFT: return button_function_critical(SHIELD_XFER_LEFT); break; // transfer shield energy to right case SHIELD_XFER_RIGHT: return button_function_critical(SHIELD_XFER_RIGHT); break; // transfer energy to shield from weapons case XFER_SHIELD: return button_function_critical(XFER_SHIELD); break; // transfer energy to weapons from shield case XFER_LASER: return button_function_critical(XFER_LASER); break; // message all netplayers button case MULTI_MESSAGE_ALL: multi_msg_key_down(MULTI_MSG_ALL); break; // message all friendlies button case MULTI_MESSAGE_FRIENDLY: multi_msg_key_down(MULTI_MSG_FRIENDLY); break; // message all hostiles button case MULTI_MESSAGE_HOSTILE: multi_msg_key_down(MULTI_MSG_HOSTILE); break; // message targeted ship (if player) case MULTI_MESSAGE_TARGET: multi_msg_key_down(MULTI_MSG_TARGET); break; // if i'm an observer, zoom to my targeted object case MULTI_OBSERVER_ZOOM_TO: multi_obs_zoom_to_target(); break; // toggle between high and low HUD contrast case TOGGLE_HUD_CONTRAST: gamesnd_play_iface(SND_USER_SELECT); hud_toggle_contrast(); break; // toggle network info case MULTI_TOGGLE_NETINFO: extern int Multi_display_netinfo; Multi_display_netinfo = !Multi_display_netinfo; break; // self destruct (multiplayer only) case MULTI_SELF_DESTRUCT: if(!(Game_mode & GM_MULTIPLAYER)){ break; } // bogus netplayer if((Net_player == NULL) || (Net_player->m_player == NULL)){ break; } // blow myself up, if I'm the server if(Net_player->flags & NETINFO_FLAG_AM_MASTER){ if((Net_player->m_player->objnum >= 0) && (Net_player->m_player->objnum < MAX_OBJECTS) && (Objects[Net_player->m_player->objnum].type == OBJ_SHIP) && (Objects[Net_player->m_player->objnum].instance >= 0) && (Objects[Net_player->m_player->objnum].instance < MAX_SHIPS)){ ship_self_destruct(&Objects[Net_player->m_player->objnum]); } } // otherwise send a packet to the server else { send_self_destruct_packet(); } break; case TOGGLE_HUD: gamesnd_play_iface(SND_USER_SELECT); hud_toggle_draw(); break; case HUD_TARGETBOX_TOGGLE_WIREFRAME: gamesnd_play_iface(SND_USER_SELECT); hud_targetbox_switch_wireframe_mode(); break; // Autopilot key control case AUTO_PILOT_TOGGLE: if (AutoPilotEngaged) { EndAutoPilot(); } else { if (CurrentNav == -1) { gamesnd_play_iface(SND_GENERAL_FAIL); } else { if (CanAutopilot()) { StartAutopilot(); } else gamesnd_play_iface(SND_GENERAL_FAIL); } } break; case NAV_CYCLE: if (!Sel_NextNav()) gamesnd_play_iface(SND_GENERAL_FAIL); break; case TOGGLE_GLIDING: control_used(TOGGLE_GLIDING); if(Player_obj != NULL) { if(object_get_gliding(Player_obj)) { object_set_gliding(Player_obj, false); } else if(Ship_info[Player_ship->ship_info_index].can_glide) { object_set_gliding(Player_obj, true); } } break; // following are not handled here, but we need to bypass the Int3() case LAUNCH_COUNTERMEASURE: case VIEW_SLEW: case VIEW_TRACK_TARGET: case ONE_THIRD_THROTTLE: case TWO_THIRDS_THROTTLE: case MINUS_5_PERCENT_THROTTLE: case PLUS_5_PERCENT_THROTTLE: case ZERO_THROTTLE: case MAX_THROTTLE: return 0; default: mprintf(("Unknown key %d at %s:%u\n", n, __FILE__, __LINE__)); // Int3(); break; } // end switch return 1; } // Call functions for when buttons are pressed void button_info_do(button_info *bi) { int i, j; for (i=0; istatus[i] == 0 ){ continue; } // at least one bit is set in the status integer for (j=0; j<32; j++) { // check if the bit is set. If button_function returns 1 (implying the action was taken), then unset the bit if ( bi->status[i] & (1 << j) ) { // always process buttons which are valid for demo playback if(button_function_demo_valid(32 * i + j)){ bi->status[i] &= ~(1 << j); } // other buttons else { // if we're in demo playback, always clear the bits if(Game_mode & GM_DEMO_PLAYBACK){ bi->status[i] &= ~(1 << j); } // otherwise check as normal else if (button_function(32 * i + j)) { bi->status[i] &= ~(1 << j); } } } } } } // set the bit for the corresponding action n (BUTTON_ #define from KeyControl.h) void button_info_set(button_info *bi, int n) { int field_num, bit_num; field_num = n / 32; bit_num = n % 32; bi->status[field_num] |= (1 << bit_num); } // unset the bit for the corresponding action n (BUTTON_ #define from KeyControl.h) void button_info_unset(button_info *bi, int n) { int field_num, bit_num; field_num = n / 32; bit_num = n % 32; bi->status[field_num] &= ~(1 << bit_num); } int button_info_query(button_info *bi, int n) { return bi->status[n / 32] & (1 << (n % 32)); } // clear out the button_info struct void button_info_clear(button_info *bi) { int i; for (i=0; istatus[i] = 0; } } // strip out all noncritical keys from the button info struct void button_strip_noncritical_keys(button_info *bi) { int idx; // clear out all noncritical keys for(idx=0;idx