LCOV - code coverage report
Current view: top level - Core/Entities - PlayerEntityControls.m (source / functions) Hit Total Coverage
Test: coverxygen.info Lines: 0 114 0.0 %
Date: 2025-05-28 07:50:54 Functions: 0 0 -

          Line data    Source code
       1           0 : /*
       2             : 
       3             : PlayerEntityControls.m
       4             : 
       5             : Oolite
       6             : Copyright (C) 2004-2019 Giles C Williams and contributors
       7             : 
       8             : This program is free software; you can redistribute it and/or
       9             : modify it under the terms of the GNU General Public License
      10             : as published by the Free Software Foundation; either version 2
      11             : of the License, or (at your option) any later version.
      12             : 
      13             : This program is distributed in the hope that it will be useful,
      14             : but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16             : GNU General Public License for more details.
      17             : 
      18             : You should have received a copy of the GNU General Public License
      19             : along with this program; if not, write to the Free Software
      20             : Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
      21             : MA 02110-1301, USA.
      22             : 
      23             : */
      24             : 
      25             : #import "PlayerEntityControls.h"
      26             : #import "PlayerEntityContracts.h"
      27             : #import "PlayerEntityLegacyScriptEngine.h"
      28             : #import "PlayerEntityScriptMethods.h"
      29             : #import "PlayerEntitySound.h"
      30             : #import "PlayerEntityLoadSave.h"
      31             : #import "PlayerEntityStickMapper.h"
      32             : #import "PlayerEntityStickProfile.h"
      33             : #import "PlayerEntityKeyMapper.h"
      34             : 
      35             : #import "ShipEntityAI.h"
      36             : #import "StationEntity.h"
      37             : #import "DockEntity.h"
      38             : #import "Universe.h"
      39             : #import "OOSunEntity.h"
      40             : #import "OOPlanetEntity.h"
      41             : #import "GameController.h"
      42             : #import "AI.h"
      43             : #import "MyOpenGLView.h"
      44             : #import "OOSound.h"
      45             : #import "OOStringParsing.h"
      46             : #import "OOCollectionExtractors.h"
      47             : #import "OOOXZManager.h"
      48             : #import "OOStringExpander.h"
      49             : #import "ResourceManager.h"
      50             : #import "HeadUpDisplay.h"
      51             : #import "OOConstToString.h"
      52             : #import "OOConstToJSString.h"
      53             : #import "OOLoggingExtended.h"
      54             : #import "OOMusicController.h"
      55             : #import "OOTexture.h"
      56             : #import "OODebugFlags.h"
      57             : 
      58             : #import "OOSystemDescriptionManager.h"
      59             : #import "OOJoystickManager.h"
      60             : 
      61             : #import "OOJSScript.h"
      62             : #import "OOEquipmentType.h"
      63             : #import "OOJSGuiScreenKeyDefinition.h"
      64             : 
      65             : #import "OODebugSupport.h"
      66             : #import "OODebugMonitor.h"
      67             : 
      68           0 : #define CUSTOM_VIEW_ROTATE_SPEED        1.0
      69           0 : #define CUSTOM_VIEW_ZOOM_SPEED          5.0
      70           0 : #define CUSTOM_VIEW_SPEED_REDUCTION_FACTOR      0.3
      71             : 
      72           0 : static BOOL                             jump_pressed;
      73           0 : static BOOL                             hyperspace_pressed;
      74           0 : static BOOL                             galhyperspace_pressed;
      75           0 : static BOOL                             pause_pressed;
      76           0 : static BOOL                             prev_compass_mode_pressed;
      77           0 : static BOOL                             next_compass_mode_pressed;
      78           0 : static BOOL                             next_target_pressed;
      79           0 : static BOOL                             previous_target_pressed;
      80           0 : static BOOL                             prime_equipment_pressed;
      81           0 : static BOOL                             activate_equipment_pressed;
      82           0 : static BOOL                             mode_equipment_pressed;
      83           0 : static BOOL                             fastactivate_a_pressed;
      84           0 : static BOOL                             fastactivate_b_pressed;
      85           0 : static BOOL                             next_missile_pressed;
      86           0 : static BOOL                             fire_missile_pressed;
      87           0 : static BOOL                             target_missile_pressed;
      88           0 : static BOOL                             target_incoming_missile_pressed;
      89           0 : static BOOL                             ident_pressed;
      90           0 : static BOOL                             safety_pressed;
      91           0 : static BOOL                             rotateCargo_pressed;
      92           0 : static BOOL                             autopilot_key_pressed;
      93           0 : static BOOL                             fast_autopilot_key_pressed;
      94           0 : static BOOL                             docking_clearance_request_key_pressed;
      95             : #ifndef NDEBUG
      96           0 : static BOOL                             dump_target_state_pressed;
      97           0 : static BOOL                             dump_entity_list_pressed;
      98             : #endif
      99           0 : static BOOL                             taking_snapshot;
     100           0 : static BOOL                             hide_hud_pressed;
     101           0 : static BOOL                             f_key_pressed;
     102           0 : static BOOL                             m_key_pressed;
     103           0 : static BOOL                             pling_pressed;
     104           0 : static BOOL                             cursor_moving;
     105           0 : static BOOL                             disc_operation_in_progress;
     106           0 : static BOOL                             f9_key_pressed;
     107             : #if OO_RESOLUTION_OPTION
     108           0 : static BOOL                             switching_resolution;
     109             : #endif
     110             : #if OOLITE_SPEECH_SYNTH
     111           0 : static BOOL                             speech_settings_pressed;
     112             : #if OOLITE_ESPEAK
     113             : static BOOL                             speechVoiceSelectKeyPressed;
     114             : static BOOL                             speechGenderSelectKeyPressed;
     115             : #endif
     116             : #endif
     117           0 : static BOOL                             wait_for_key_up;
     118           0 : static BOOL                             upDownKeyPressed;
     119           0 : static BOOL                             pageUpDownKeyPressed;
     120           0 : static BOOL                             leftRightKeyPressed;
     121           0 : static BOOL                             musicModeKeyPressed;
     122           0 : static BOOL                             volumeControlPressed;
     123             : #if OOLITE_SDL
     124             : static BOOL                             gammaControlPressed;
     125             : #endif
     126           0 : static BOOL                             fovControlPressed;
     127           0 : static BOOL                             hdrMaxBrightnessControlPressed;
     128           0 : static BOOL                             hdrPaperWhiteControlPressed;
     129           0 : static BOOL                             colorblindModeControlPressed;
     130           0 : static BOOL                             shaderSelectKeyPressed;
     131           0 : static BOOL                             selectPressed;
     132           0 : static BOOL                             queryPressed;
     133           0 : static BOOL                             spacePressed;
     134           0 : static BOOL                             chartInfoPressed;
     135           0 : static BOOL                             switching_chart_screens;
     136           0 : static BOOL                             switching_status_screens;
     137             : //static BOOL                           switching_market_screens;
     138           0 : static BOOL                             switching_equipship_screens;
     139           0 : static BOOL                             zoom_pressed;
     140           0 : static BOOL                             customView_pressed;
     141           0 : static BOOL                             weaponsOnlineToggle_pressed;
     142           0 : static BOOL                             escapePodKey_pressed;
     143           0 : static BOOL                             cycleMFD_pressed;
     144           0 : static BOOL                             switchMFD_pressed;
     145           0 : static BOOL                             mouse_left_down;
     146           0 : static BOOL                             oxz_manager_pressed;
     147           0 : static BOOL                             next_planet_info_pressed;
     148           0 : static BOOL                             previous_planet_info_pressed;
     149           0 : static BOOL                             home_info_pressed;
     150           0 : static BOOL                             target_info_pressed;
     151           0 : static BOOL                             extra_key_pressed;
     152           0 : static BOOL                             extra_gui_key_pressed;
     153           0 : static NSPoint                          mouse_click_position;
     154           0 : static NSPoint                          centre_at_mouse_click;
     155             : 
     156             : 
     157           0 : static NSUInteger               searchStringLength;
     158           0 : static double                   timeLastKeyPress;
     159             : //static OOGUIRow                       oldSelection;
     160           0 : static int                              saved_view_direction;
     161           0 : static double                   saved_script_time;
     162           0 : static int                              saved_gui_screen;
     163           0 : static OOWeaponFacing   saved_weapon_facing;
     164           0 : static int                              pressedArrow = 0;
     165           0 : static BOOL                             mouse_x_axis_map_to_yaw = NO;
     166           0 : static NSTimeInterval   time_last_frame;
     167             : 
     168             : 
     169             : @interface PlayerEntity (OOControlsPrivate)
     170             : 
     171           0 : - (void) pollFlightControls:(double) delta_t;
     172           0 : - (void) pollFlightArrowKeyControls:(double) delta_t;
     173           0 : - (void) pollGuiArrowKeyControls:(double) delta_t;
     174           0 : - (void) handleGameOptionsScreenKeys;
     175           0 : - (void) handleKeyMapperScreenKeys;
     176           0 : - (void) handleKeyboardLayoutKeys;
     177           0 : - (void) handleStickMapperScreenKeys;
     178           0 : - (void) pollApplicationControls;
     179           0 : - (void) pollCustomViewControls;
     180           0 : - (void) pollViewControls;
     181           0 : - (void) pollGuiScreenControls;
     182           0 : - (void) pollGuiScreenControlsWithFKeyAlias:(BOOL)fKeyAlias;
     183           0 : - (void) pollMarketScreenControls;
     184           0 : - (void) handleUndockControl;
     185           0 : - (void) pollGameOverControls:(double) delta_t;
     186           0 : - (void) pollAutopilotControls:(double) delta_t;
     187           0 : - (void) pollDockedControls:(double) delta_t;
     188           0 : - (void) pollDemoControls:(double) delta_t;
     189           0 : - (void) pollMissionInterruptControls;
     190           0 : - (void) handleMissionCallback;
     191           0 : - (void) setGuiToMissionEndScreen;
     192           0 : - (void) switchToThisView:(OOViewID)viewDirection;
     193           0 : - (void) switchToThisView:(OOViewID)viewDirection andProcessWeaponFacing:(BOOL)processWeaponFacing;
     194           0 : - (void) switchToThisView:(OOViewID)viewDirection fromView:(OOViewID)oldViewDirection andProcessWeaponFacing:(BOOL)processWeaponFacing justNotify:(BOOL)justNotify;
     195             : 
     196           0 : - (void) handleAutopilotOn:(BOOL)fastDocking;
     197             : 
     198             : // Handlers for individual controls
     199           0 : - (void) handleButtonIdent;
     200           0 : - (void) handleButtonTargetMissile;
     201             : @end
     202             : 
     203             : 
     204             : @implementation PlayerEntity (Controls)
     205             : 
     206             : - (void) initControls
     207             : {
     208             :         [keyCodeLookups release];
     209             :         // all entries in this dict must be in lowercase
     210             :         keyCodeLookups = [[NSDictionary alloc] initWithObjectsAndKeys:
     211             :                 [NSNumber numberWithUnsignedShort:gvArrowKeyLeft], @"arrowleft", 
     212             :                 [NSNumber numberWithUnsignedShort:gvArrowKeyLeft], @"leftarrow", 
     213             :                 [NSNumber numberWithUnsignedShort:gvArrowKeyLeft], @"left", 
     214             :                 [NSNumber numberWithUnsignedShort:gvArrowKeyRight], @"arrowright", 
     215             :                 [NSNumber numberWithUnsignedShort:gvArrowKeyRight], @"rightarrow", 
     216             :                 [NSNumber numberWithUnsignedShort:gvArrowKeyRight], @"right", 
     217             :                 [NSNumber numberWithUnsignedShort:gvArrowKeyUp], @"arrowup", 
     218             :                 [NSNumber numberWithUnsignedShort:gvArrowKeyUp], @"uparrow", 
     219             :                 [NSNumber numberWithUnsignedShort:gvArrowKeyUp], @"up", 
     220             :                 [NSNumber numberWithUnsignedShort:gvArrowKeyDown], @"arrowdown", 
     221             :                 [NSNumber numberWithUnsignedShort:gvArrowKeyDown], @"downarrow", 
     222             :                 [NSNumber numberWithUnsignedShort:gvArrowKeyDown], @"down", 
     223             :                 [NSNumber numberWithUnsignedShort:gvPageUpKey], @"pageup", 
     224             :                 [NSNumber numberWithUnsignedShort:gvPageDownKey], @"pagedown", 
     225             :                 [NSNumber numberWithUnsignedShort:13], @"enter", 
     226             :                 [NSNumber numberWithUnsignedShort:13], @"return", 
     227             :                 [NSNumber numberWithUnsignedShort:27], @"escape", 
     228             :                 [NSNumber numberWithUnsignedShort:27], @"esc", 
     229             :                 [NSNumber numberWithUnsignedShort:9], @"tab", 
     230             :                 [NSNumber numberWithUnsignedShort:32], @"space", 
     231             :                 [NSNumber numberWithUnsignedShort:32], @"spc", 
     232             :                 [NSNumber numberWithUnsignedShort:gvHomeKey], @"home", 
     233             :                 [NSNumber numberWithUnsignedShort:gvEndKey], @"end", 
     234             :                 [NSNumber numberWithUnsignedShort:gvDeleteKey], @"delete", 
     235             :                 [NSNumber numberWithUnsignedShort:gvDeleteKey], @"del", 
     236             :                 [NSNumber numberWithUnsignedShort:gvBackspaceKey], @"backspace", 
     237             :                 [NSNumber numberWithUnsignedShort:gvBackspaceKey], @"backspc", 
     238             :                 [NSNumber numberWithUnsignedShort:gvBackspaceKey], @"bkspace", 
     239             :                 [NSNumber numberWithUnsignedShort:gvBackspaceKey], @"bkspc", 
     240             :                 [NSNumber numberWithUnsignedShort:gvInsertKey], @"insert", 
     241             :                 [NSNumber numberWithUnsignedShort:gvInsertKey], @"ins", 
     242             :                 [NSNumber numberWithUnsignedShort:gvFunctionKey1], @"f1", 
     243             :                 [NSNumber numberWithUnsignedShort:gvFunctionKey2], @"f2", 
     244             :                 [NSNumber numberWithUnsignedShort:gvFunctionKey3], @"f3", 
     245             :                 [NSNumber numberWithUnsignedShort:gvFunctionKey4], @"f4", 
     246             :                 [NSNumber numberWithUnsignedShort:gvFunctionKey5], @"f5", 
     247             :                 [NSNumber numberWithUnsignedShort:gvFunctionKey6], @"f6", 
     248             :                 [NSNumber numberWithUnsignedShort:gvFunctionKey7], @"f7", 
     249             :                 [NSNumber numberWithUnsignedShort:gvFunctionKey8], @"f8", 
     250             :                 [NSNumber numberWithUnsignedShort:gvFunctionKey9], @"f9", 
     251             :                 [NSNumber numberWithUnsignedShort:gvFunctionKey10], @"f10", 
     252             :                 [NSNumber numberWithUnsignedShort:gvFunctionKey11], @"f11", 
     253             :                 [NSNumber numberWithUnsignedShort:gvPauseKey], @"pause",
     254             :                 [NSNumber numberWithUnsignedShort:gvPrintScreenKey], @"printscreen",
     255             :                 [NSNumber numberWithUnsignedShort:gvPrintScreenKey], @"prtscrn",
     256             :                 [NSNumber numberWithUnsignedShort:gvPrintScreenKey], @"prntscrn",
     257             :                 [NSNumber numberWithUnsignedShort:gvPrintScreenKey], @"prtscn",
     258             :                 [NSNumber numberWithUnsignedShort:gvNumberPadKey0], @"numpad0", 
     259             :                 [NSNumber numberWithUnsignedShort:gvNumberPadKey1], @"numpad1", 
     260             :                 [NSNumber numberWithUnsignedShort:gvNumberPadKey2], @"numpad2", 
     261             :                 [NSNumber numberWithUnsignedShort:gvNumberPadKey3], @"numpad3", 
     262             :                 [NSNumber numberWithUnsignedShort:gvNumberPadKey4], @"numpad4", 
     263             :                 [NSNumber numberWithUnsignedShort:gvNumberPadKey5], @"numpad5", 
     264             :                 [NSNumber numberWithUnsignedShort:gvNumberPadKey6], @"numpad6", 
     265             :                 [NSNumber numberWithUnsignedShort:gvNumberPadKey7], @"numpad7", 
     266             :                 [NSNumber numberWithUnsignedShort:gvNumberPadKey8], @"numpad8", 
     267             :                 [NSNumber numberWithUnsignedShort:gvNumberPadKey9], @"numpad9", 
     268             :                 [NSNumber numberWithUnsignedShort:gvNumberPadKeyDivide], @"numpad/",
     269             :                 [NSNumber numberWithUnsignedShort:gvNumberPadKeyDivide], @"numpaddivide",
     270             :                 [NSNumber numberWithUnsignedShort:gvNumberPadKeyMultiply], @"numpad*",
     271             :                 [NSNumber numberWithUnsignedShort:gvNumberPadKeyMultiply], @"numpadmultiply",
     272             :                 [NSNumber numberWithUnsignedShort:gvNumberPadKeyMinus], @"numpad-",
     273             :                 [NSNumber numberWithUnsignedShort:gvNumberPadKeyMinus], @"numpadminus",
     274             :                 [NSNumber numberWithUnsignedShort:gvNumberPadKeyPlus], @"numpad+",
     275             :                 [NSNumber numberWithUnsignedShort:gvNumberPadKeyPlus], @"numpadplus",
     276             :                 [NSNumber numberWithUnsignedShort:gvNumberPadKeyPeriod], @"numpad.",
     277             :                 [NSNumber numberWithUnsignedShort:gvNumberPadKeyPeriod], @"numpadperiod",
     278             :                 [NSNumber numberWithUnsignedShort:gvNumberPadKeyEquals], @"numpad=",
     279             :                 [NSNumber numberWithUnsignedShort:gvNumberPadKeyEquals], @"numpadequals",
     280             :                 [NSNumber numberWithUnsignedShort:gvNumberPadKeyEnter], @"numpadenter", nil];
     281             : 
     282             :         keyShiftText = [DESC(@"oolite-keyconfig-shift") retain];
     283             :         keyMod1Text = [DESC(@"oolite-keyconfig-mod1") retain];
     284             : #if OOLITE_MAC_OS_X
     285             :         keyMod2Text = [DESC(@"oolite-keyconfig-mod2-mac") retain];
     286             : #else
     287             :         keyMod2Text = [DESC(@"oolite-keyconfig-mod2-pc") retain];
     288             : #endif
     289             : 
     290             :         [self initKeyConfigSettings];
     291             : 
     292             :         // Enable polling
     293             :         pollControls=YES;
     294             : }
     295             : 
     296             : - (void) initKeyConfigSettings
     297             : {
     298             :         NSMutableDictionary     *kdicmaster = [NSMutableDictionary dictionaryWithDictionary:[ResourceManager dictionaryFromFilesNamed:@"keyconfig2.plist" inFolder:@"Config" mergeMode:MERGE_BASIC cache:NO]];
     299             :         NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
     300             :         NSString *kbd = [defaults oo_stringForKey:@"keyboard-code" defaultValue:@"default"];
     301             :         NSMutableDictionary *kdic2 = [NSMutableDictionary dictionaryWithDictionary:[kdicmaster objectForKey:kbd]];
     302             : 
     303             :         unsigned                i;
     304             :         NSArray                 *keys = nil;
     305             :         id                              key = nil;
     306             :         NSArray                 *def_list = nil;
     307             : 
     308             :         keys = [kdic2 allKeys];
     309             :         for (i = 0; i < [keys count]; i++)
     310             :         {
     311             :                 key = [keys objectAtIndex:i];
     312             :                 if ([[kdic2 objectForKey:key] isKindOfClass:[NSArray class]])
     313             :                 {
     314             :                         def_list = (NSArray*)[kdic2 objectForKey: key];
     315             :                         [kdic2 setObject:[self processKeyCode:def_list] forKey:key];
     316             :                 }
     317             :         }
     318             : 
     319             :         // load custom equipment keys/buttons
     320             :         [customEquipActivation release];
     321             :         if ([defaults objectForKey:KEYCONFIG_CUSTOMEQUIP]) 
     322             :         {
     323             :                 NSArray *temp = [defaults arrayForKey:KEYCONFIG_CUSTOMEQUIP];
     324             :                 customEquipActivation = [[NSMutableArray arrayWithArray:temp] retain];
     325             :         }
     326             :         else 
     327             :         {
     328             :                 customEquipActivation = [[NSMutableArray alloc] init];
     329             :         }
     330             :         [customActivatePressed release];
     331             :         [customModePressed release];
     332             :         customActivatePressed = [[NSMutableArray alloc] init];
     333             :         customModePressed = [[NSMutableArray alloc] init];
     334             :         for (i = 0; i < [customEquipActivation count]; i++)
     335             :         {
     336             :                 [customActivatePressed addObject:[NSNumber numberWithBool:NO]];
     337             :                 [customModePressed addObject:[NSNumber numberWithBool:NO]];
     338             :         }
     339             : 
     340             :         NSMutableArray *keyDef = nil;
     341             :         NSString *lookup = nil;
     342             :         NSArray *curr = nil;
     343             :         NSDictionary *key1 = nil;
     344             :         NSDictionary *key2 = nil;
     345             : 
     346             :         // update with overrides from defaults file
     347             :         NSDictionary *dict = [defaults objectForKey:KEYCONFIG_OVERRIDES];
     348             : 
     349             :         keys = [dict allKeys];
     350             :         for (i = 0; i < [keys count]; i++)
     351             :         {
     352             :                 key = [keys objectAtIndex:i];
     353             :                 [kdic2 setObject:[dict objectForKey:key] forKey:key];
     354             :         }
     355             : 
     356             : // by default none of the standard key functions require more than 2 entries, so our macro will limit itself to 2
     357             : // also, none of the standard key functions utilise "Alt" (mod2), so we're defaulting that setting
     358           0 : #define LOAD_KEY_SETTING2(name, default_1, shift_1, mod1_1, default_2, shift_2, mod1_2) \
     359             :         lookup = [@#name substringFromIndex:2]; \
     360             :         curr = (NSArray*)[[kdic2 objectForKey:lookup] copy]; \
     361             :         key1 = [[NSDictionary alloc] initWithObjectsAndKeys:[NSNumber numberWithUnsignedShort:default_1], @"key", [NSNumber numberWithBool:shift_1], @"shift", [NSNumber numberWithBool:mod1_1], @"mod1", [NSNumber numberWithBool:NO], @"mod2", nil]; \
     362             :         [keyDef addObject:key1]; \
     363             :         if (default_2 > 0) \
     364             :         { \
     365             :                 key2 = [[NSDictionary alloc] initWithObjectsAndKeys:[NSNumber numberWithUnsignedShort:default_2], @"key", [NSNumber numberWithBool:shift_2], @"shift", [NSNumber numberWithBool:mod1_2], @"mod1", [NSNumber numberWithBool:NO], @"mod2", nil]; \
     366             :                 [keyDef addObject:key2]; \
     367             :         } \
     368             :         name = curr?:keyDef; \
     369             :         [kdic2 setObject:curr?:keyDef forKey:lookup]; \
     370             :         [keyDef release];
     371             : 
     372             :         LOAD_KEY_SETTING2(n_key_roll_left, gvArrowKeyLeft, NO, NO, 0, NO, NO);
     373             :         LOAD_KEY_SETTING2(n_key_roll_right,     gvArrowKeyRight, NO, NO, 0, NO, NO);
     374             :         LOAD_KEY_SETTING2(n_key_pitch_forward, gvArrowKeyUp, NO, NO, 0, NO, NO);
     375             :         LOAD_KEY_SETTING2(n_key_pitch_back, gvArrowKeyDown, NO, NO, 0, NO, NO);
     376             :         LOAD_KEY_SETTING2(n_key_yaw_left, ',', NO, NO, 0, NO, NO);
     377             :         LOAD_KEY_SETTING2(n_key_yaw_right, '.', NO, NO, 0, NO, NO);
     378             : 
     379             :         LOAD_KEY_SETTING2(n_key_view_forward, '1', NO, NO, gvFunctionKey1, NO, NO);
     380             :         LOAD_KEY_SETTING2(n_key_view_aft, '2', NO, NO, gvFunctionKey2, NO, NO);
     381             :         LOAD_KEY_SETTING2(n_key_view_port, '3', NO, NO, gvFunctionKey3, NO, NO);
     382             :         LOAD_KEY_SETTING2(n_key_view_starboard, '4', NO, NO, gvFunctionKey4, NO, NO);
     383             : 
     384             :         LOAD_KEY_SETTING2(n_key_launch_ship, '1', NO, NO, gvFunctionKey1, NO, NO);
     385             :         LOAD_KEY_SETTING2(n_key_gui_screen_options, '2', NO, NO, gvFunctionKey2, NO, NO);
     386             :         LOAD_KEY_SETTING2(n_key_gui_screen_equipship, '3', NO, NO, gvFunctionKey3, NO, NO);
     387             :         LOAD_KEY_SETTING2(n_key_gui_screen_interfaces, '4', NO, NO, gvFunctionKey4, NO, NO);
     388             :         LOAD_KEY_SETTING2(n_key_gui_screen_status, '5', NO, NO, gvFunctionKey5, NO, NO);
     389             :         LOAD_KEY_SETTING2(n_key_gui_chart_screens, '6', NO, NO, gvFunctionKey6, NO, NO);
     390             :         LOAD_KEY_SETTING2(n_key_gui_system_data, '7', NO, NO, gvFunctionKey7, NO, NO);
     391             :         LOAD_KEY_SETTING2(n_key_gui_market, '8', NO, NO, gvFunctionKey8, NO, NO);
     392             : 
     393             :         LOAD_KEY_SETTING2(n_key_gui_arrow_left, gvArrowKeyLeft, NO, NO, 0, NO, NO);
     394             :         LOAD_KEY_SETTING2(n_key_gui_arrow_right, gvArrowKeyRight, NO, NO, 0, NO, NO);
     395             :         LOAD_KEY_SETTING2(n_key_gui_arrow_up, gvArrowKeyUp, NO, NO, 0, NO, NO);
     396             :         LOAD_KEY_SETTING2(n_key_gui_arrow_down, gvArrowKeyDown, NO, NO, 0, NO, NO);
     397             :         LOAD_KEY_SETTING2(n_key_gui_page_up, gvPageUpKey, NO, NO, 0, NO, NO);
     398             :         LOAD_KEY_SETTING2(n_key_gui_page_down, gvPageDownKey, NO, NO, 0, NO, NO);
     399             :         LOAD_KEY_SETTING2(n_key_gui_select, 13, NO, NO, gvNumberPadKeyEnter, NO, NO);
     400             :         
     401             :         LOAD_KEY_SETTING2(n_key_increase_speed, 'w', NO, NO, 0, NO, NO);
     402             :         LOAD_KEY_SETTING2(n_key_decrease_speed, 's', NO, NO, 0, NO, NO);
     403             :         LOAD_KEY_SETTING2(n_key_inject_fuel, 'i', NO, NO, 0, NO, NO);
     404             :         
     405             :         LOAD_KEY_SETTING2(n_key_fire_lasers, 'a', NO, NO, 0, NO, NO);
     406             :         LOAD_KEY_SETTING2(n_key_weapons_online_toggle, '_', YES, NO, 0, NO, NO);
     407             :         LOAD_KEY_SETTING2(n_key_launch_missile, 'm', NO, NO, 0, NO, NO);
     408             :         LOAD_KEY_SETTING2(n_key_next_missile, 'y', NO, NO, 0, NO, NO);
     409             :         LOAD_KEY_SETTING2(n_key_ecm, 'e', NO, NO, 0, NO, NO);
     410             :         
     411             :         LOAD_KEY_SETTING2(n_key_prime_next_equipment, 'N', YES, NO, 0, NO, NO);
     412             :         LOAD_KEY_SETTING2(n_key_prime_previous_equipment, 'N', YES, YES, 0, NO, NO);
     413             :         LOAD_KEY_SETTING2(n_key_activate_equipment, 'n', NO, NO, 0, NO, NO);
     414             :         LOAD_KEY_SETTING2(n_key_mode_equipment, 'b', NO, NO, 0, NO, NO);
     415             :         LOAD_KEY_SETTING2(n_key_fastactivate_equipment_a, '0', NO, NO, 0, NO, NO);
     416             :         LOAD_KEY_SETTING2(n_key_fastactivate_equipment_b, 9, NO, NO, 0, NO, NO);
     417             :         
     418             :         LOAD_KEY_SETTING2(n_key_target_missile, 't', NO, NO, 0, NO, NO);
     419             :         LOAD_KEY_SETTING2(n_key_untarget_missile, 'u', NO, NO, 0, NO, NO);
     420             :         LOAD_KEY_SETTING2(n_key_target_incoming_missile, 'T', YES, NO, 0, NO, NO);
     421             :         LOAD_KEY_SETTING2(n_key_ident_system, 'r', NO, NO, 0, NO, NO);
     422             :         
     423             :         LOAD_KEY_SETTING2(n_key_scanner_zoom, 'z', NO, NO, 0, NO, NO);
     424             :         LOAD_KEY_SETTING2(n_key_scanner_unzoom, 'Z', YES, NO, 0, NO, NO);
     425             :         
     426             :         LOAD_KEY_SETTING2(n_key_launch_escapepod, 27, NO, NO, 0, NO, NO);
     427             :         
     428             :         LOAD_KEY_SETTING2(n_key_galactic_hyperspace, 'g', NO, NO, 0, NO, NO);
     429             :         LOAD_KEY_SETTING2(n_key_hyperspace, 'h', NO, NO, 0, NO, NO);
     430             :         LOAD_KEY_SETTING2(n_key_jumpdrive, 'j', NO, NO, 0, NO, NO);
     431             :         
     432             :         LOAD_KEY_SETTING2(n_key_dump_cargo, 'D', YES, NO, 0, NO, NO);
     433             :         LOAD_KEY_SETTING2(n_key_rotate_cargo, 'R', YES, NO, 0, NO, NO);
     434             :         
     435             :         LOAD_KEY_SETTING2(n_key_autopilot, 'c', NO, NO, 0, NO, NO);
     436             :         LOAD_KEY_SETTING2(n_key_autodock, 'C', YES, NO, 0, NO, NO);
     437             :         LOAD_KEY_SETTING2(n_key_docking_clearance_request, 'L', YES, NO, 0, NO, NO);
     438             :         
     439             :         LOAD_KEY_SETTING2(n_key_snapshot, '*', YES, NO, gvNumberPadKeyMultiply, NO, NO);
     440             :         LOAD_KEY_SETTING2(n_key_docking_music, 's', NO, NO, 0, NO, NO);
     441             :         
     442             :         LOAD_KEY_SETTING2(n_key_advanced_nav_array_next, '^', YES, NO, 0, NO, NO);
     443             :         LOAD_KEY_SETTING2(n_key_advanced_nav_array_previous, '^', YES, YES, 0, NO, NO);
     444             :         LOAD_KEY_SETTING2(n_key_map_home, gvHomeKey, NO, NO, 0, NO, NO);
     445             :         LOAD_KEY_SETTING2(n_key_map_end, gvEndKey, NO, NO, 0, NO, NO);
     446             :         LOAD_KEY_SETTING2(n_key_map_next_system, gvArrowKeyRight, NO, NO, gvArrowKeyDown, NO, NO);
     447             :         LOAD_KEY_SETTING2(n_key_map_previous_system, gvArrowKeyLeft, NO, NO, gvArrowKeyUp, NO, NO);
     448             :         LOAD_KEY_SETTING2(n_key_map_zoom_in, gvPageDownKey, NO, NO, 0, NO, NO);
     449             :         LOAD_KEY_SETTING2(n_key_map_zoom_out, gvPageUpKey, NO, NO, 0, NO, NO);
     450             :         LOAD_KEY_SETTING2(n_key_map_info, 'i', NO, NO, 0, NO, NO);
     451             :         LOAD_KEY_SETTING2(n_key_chart_highlight, '?', YES, NO, 0, NO, NO);
     452             : 
     453             :         LOAD_KEY_SETTING2(n_key_system_home, gvHomeKey, NO, NO, 0, NO, NO);
     454             :         LOAD_KEY_SETTING2(n_key_system_end, gvEndKey, NO, NO, 0, NO, NO);
     455             :         LOAD_KEY_SETTING2(n_key_system_next_system, gvArrowKeyRight, NO, NO, gvArrowKeyDown, NO, NO);
     456             :         LOAD_KEY_SETTING2(n_key_system_previous_system, gvArrowKeyLeft, NO, NO, gvArrowKeyUp, NO, NO);
     457             : 
     458             :         LOAD_KEY_SETTING2(n_key_pausebutton, 'p', NO, NO, 0, NO, NO);
     459             :         LOAD_KEY_SETTING2(n_key_show_fps, 'F', YES, NO, 0, NO, NO);
     460             :         LOAD_KEY_SETTING2(n_key_bloom_toggle, gvFunctionKey9, YES, NO, 0, NO, NO);
     461             :         LOAD_KEY_SETTING2(n_key_mouse_control_roll, 'M', YES, NO, 0, NO, NO);
     462             :         LOAD_KEY_SETTING2(n_key_mouse_control_yaw, 'M', YES, YES, 0, NO, NO);
     463             :         LOAD_KEY_SETTING2(n_key_hud_toggle, 'o', NO, NO, 0, NO, NO);
     464             :         
     465             :         LOAD_KEY_SETTING2(n_key_comms_log, '`', YES, NO, 0, NO, NO);
     466             :         LOAD_KEY_SETTING2(n_key_prev_compass_mode, '|', YES, NO, 0, NO, NO);
     467             :         LOAD_KEY_SETTING2(n_key_next_compass_mode, '\\', NO, NO, 0, NO, NO);
     468             :         
     469             :         LOAD_KEY_SETTING2(n_key_market_filter_cycle, '?', YES, NO, 0, NO, NO);
     470             :         LOAD_KEY_SETTING2(n_key_market_sorter_cycle, '/', NO, NO, gvNumberPadKeyDivide, NO, NO);
     471             :         LOAD_KEY_SETTING2(n_key_market_buy_one, gvArrowKeyRight, NO, NO, 0, NO, NO);
     472             :         LOAD_KEY_SETTING2(n_key_market_sell_one, gvArrowKeyLeft, NO, NO, 0, NO, NO);
     473             :         LOAD_KEY_SETTING2(n_key_market_buy_max, gvArrowKeyRight, YES, NO, 0, NO, NO);
     474             :         LOAD_KEY_SETTING2(n_key_market_sell_max, gvArrowKeyLeft, YES, NO, 0, NO, NO);
     475             : 
     476             :         LOAD_KEY_SETTING2(n_key_cycle_next_mfd, ';', NO, NO, 0, NO, NO);
     477             :         LOAD_KEY_SETTING2(n_key_cycle_previous_mfd, ';', NO, YES, 0, NO, NO);
     478             :         LOAD_KEY_SETTING2(n_key_switch_next_mfd, ':', YES, NO, 0, NO, NO);
     479             :         LOAD_KEY_SETTING2(n_key_switch_previous_mfd, ':', YES, YES, 0, NO, NO);
     480             : 
     481             :         LOAD_KEY_SETTING2(n_key_next_target, '+', YES, NO, gvNumberPadKeyPlus, NO, NO);
     482             :         LOAD_KEY_SETTING2(n_key_previous_target, '-', NO, NO, gvNumberPadKeyMinus, NO, NO);
     483             :         
     484             :         LOAD_KEY_SETTING2(n_key_custom_view, 'v', NO, NO, 0, NO, NO);
     485             :         LOAD_KEY_SETTING2(n_key_custom_view_zoom_out, gvPageDownKey, NO, NO, 0, NO, NO);
     486             :         LOAD_KEY_SETTING2(n_key_custom_view_zoom_in, gvPageUpKey, NO, NO, 0, NO, NO);
     487             :         LOAD_KEY_SETTING2(n_key_custom_view_roll_left, gvArrowKeyLeft, NO, NO, 0, NO, NO);
     488             :         LOAD_KEY_SETTING2(n_key_custom_view_pan_left, gvArrowKeyLeft, YES, NO, 0, NO, NO);
     489             :         LOAD_KEY_SETTING2(n_key_custom_view_roll_right, gvArrowKeyRight, NO, NO, 0, NO, NO);
     490             :         LOAD_KEY_SETTING2(n_key_custom_view_pan_right, gvArrowKeyRight, YES, NO, 0, NO, NO);
     491             :         LOAD_KEY_SETTING2(n_key_custom_view_rotate_up, gvArrowKeyUp, NO, NO, 0, NO, NO);
     492             :         LOAD_KEY_SETTING2(n_key_custom_view_pan_up, gvArrowKeyUp, YES, NO, 0, NO, NO);
     493             :         LOAD_KEY_SETTING2(n_key_custom_view_rotate_down, gvArrowKeyDown, NO, NO, 0, NO, NO);
     494             :         LOAD_KEY_SETTING2(n_key_custom_view_pan_down, gvArrowKeyDown, YES, NO, 0, NO, NO);
     495             :         LOAD_KEY_SETTING2(n_key_custom_view_rotate_left, ',', NO, NO, 0, NO, NO);
     496             :         LOAD_KEY_SETTING2(n_key_custom_view_rotate_right, '.', NO, NO, 0, NO, NO);
     497             : 
     498             :         LOAD_KEY_SETTING2(n_key_oxzmanager_setfilter, 'f', NO, NO, 0, NO, NO);
     499             :         LOAD_KEY_SETTING2(n_key_oxzmanager_showinfo, 'i', NO, NO, 0, NO, NO);
     500             :         LOAD_KEY_SETTING2(n_key_oxzmanager_extract, 'x', NO, NO, 0, NO, NO);
     501             :         
     502             : #if OO_FOV_INFLIGHT_CONTROL_ENABLED
     503             :         LOAD_KEY_SETTING2(n_key_inc_field_of_view, 'l', NO, NO, 0, NO, NO);
     504             :         LOAD_KEY_SETTING2(n_key_dec_field_of_view, 'k', NO, NO, 0, NO, NO);
     505             : #endif
     506             : 
     507             : #ifndef NDEBUG
     508             :         LOAD_KEY_SETTING2(n_key_dump_target_state, 'H', YES, NO, 0, NO, NO);
     509             :         LOAD_KEY_SETTING2(n_key_dump_entity_list, '0', NO, NO, 0, NO, NO);
     510             :         LOAD_KEY_SETTING2(n_key_debug_full, 'd', NO, NO, 0, NO, NO);
     511             :         LOAD_KEY_SETTING2(n_key_debug_collision, 'b', NO, NO, 0, NO, NO);
     512             :         LOAD_KEY_SETTING2(n_key_debug_console_connect, 'c', NO, NO, 0, NO, NO);
     513             :         LOAD_KEY_SETTING2(n_key_debug_bounding_boxes, 'x', NO, NO, 0, NO, NO);
     514             :         LOAD_KEY_SETTING2(n_key_debug_shaders, 's', NO, NO, 0, NO, NO);
     515             :         LOAD_KEY_SETTING2(n_key_debug_off, 'n', NO, NO, 0, NO, NO);
     516             : #endif
     517             : 
     518             :         [keyconfig2_settings release];
     519             :         keyconfig2_settings = [[NSDictionary alloc] initWithDictionary:kdic2 copyItems:YES];
     520             : }
     521             : 
     522             : 
     523             : - (NSArray*) processKeyCode:(NSArray*)key_def
     524             : {
     525             :         int i;
     526             :         id                              key = nil, value = nil;
     527             :         int                             iValue;
     528             :         unsigned char   keychar;
     529             :         NSString                *keystring = nil;
     530             :         NSDictionary    *def = nil;
     531             :         NSMutableArray  *newList = [[NSMutableArray alloc] init];
     532             : 
     533             :         for (i = 0; i < [key_def count]; i++) 
     534             :         {
     535             :                 def = [key_def objectAtIndex:i];
     536             :                 if ([def count] == 0) continue; // skip this if the definition is empty
     537             :                 value = [def objectForKey:@"key"];
     538             :                 iValue = [value intValue];
     539             : 
     540             :                 // we're going to fully expand all the shift/mod1/mod2 properties for all the key setting with defaults
     541             :                 // to avoid the need to check for the presence of a property during game loops
     542             :                 NSMutableDictionary *defNew = [[NSMutableDictionary alloc] init];
     543             :                 if ([def objectForKey:@"shift"]) [defNew setObject:[def objectForKey:@"shift"] forKey:@"shift"]; else [defNew setObject:[NSNumber numberWithBool:NO] forKey:@"shift"];
     544             :                 if ([def objectForKey:@"mod1"]) [defNew setObject:[def objectForKey:@"mod1"] forKey:@"mod1"]; else [defNew setObject:[NSNumber numberWithBool:NO] forKey:@"mod1"];
     545             :                 if ([def objectForKey:@"mod2"]) [defNew setObject:[def objectForKey:@"mod2"] forKey:@"mod2"]; else [defNew setObject:[NSNumber numberWithBool:NO] forKey:@"mod2"];
     546             : 
     547             :                 //      for '0' '1' '2' '3' '4' '5' '6' '7' '8' '9' - we want to interpret those as strings - not numbers
     548             :                 //      alphabetical characters and symbols will return an intValue of 0.
     549             :                 
     550             :                 if ([value isKindOfClass:[NSString class]] && (iValue < 10))
     551             :                 {
     552             :                         keystring = value;
     553             : 
     554             :                         // check for a named lookup
     555             :                         if ([keystring length] != 0)
     556             :                         {
     557             :                                 int checkVal;
     558             :                                 checkVal = [[keyCodeLookups objectForKey:[keystring lowercaseString]] intValue];
     559             :                                 if (checkVal > 0) {
     560             :                                         iValue = checkVal;
     561             : 
     562             :                                         [defNew setObject:[NSNumber numberWithUnsignedShort:iValue] forKey:@"key"];
     563             :                                         [newList addObject:defNew];
     564             :                                         [defNew release];
     565             :                                         continue;
     566             :                                 }
     567             :                         }
     568             : 
     569             :                         if ([keystring length] == 1 || (iValue == 0 && [keystring length] != 0))
     570             :                         {
     571             :                                 keychar = [keystring characterAtIndex:0] & 0x00ff; // uses lower byte of unichar
     572             :                         }
     573             :                         else if (iValue <= 0xFF) keychar = iValue;
     574             :                         else {
     575             :                                 OOLogWARN(@"testing", @"continue hit for key %@.", key);
     576             :                                 [defNew setObject:[def objectForKey:@"key"] forKey:@"key"];
     577             :                                 [newList addObject:defNew];
     578             :                                 [defNew release];
     579             :                                 continue;
     580             :                         }
     581             :                 
     582             :                         [defNew setObject:[NSNumber numberWithUnsignedShort:keychar] forKey:@"key"];
     583             :                         [newList addObject:defNew];
     584             :                         [defNew release];
     585             :                 } 
     586             :                 else 
     587             :                 {
     588             :                         [defNew setObject:[def objectForKey:@"key"] forKey:@"key"];
     589             :                         [newList addObject:defNew];
     590             :                         [defNew release];
     591             :                 }
     592             :         }
     593             : 
     594             :         return newList;
     595             : }
     596             : 
     597             : 
     598             : // special case for navigation keys - these keys cannot use mod keys, so they can't be impacted by multiple keypresses
     599             : - (BOOL) checkNavKeyPress:(NSArray*)key_def
     600             : {
     601             :         MyOpenGLView  *gameView = [UNIVERSE gameView];
     602             :         int i;
     603             :         for (i = 0; i < [key_def count]; i++) 
     604             :         {
     605             :                 NSDictionary *def = [key_def objectAtIndex:i];
     606             :                 if ([gameView isDown:[[def objectForKey:@"key"] intValue]]) return YES;
     607             :         }
     608             :         return NO;
     609             : }
     610             : 
     611             : 
     612             : - (BOOL) checkKeyPress:(NSArray*)key_def
     613             : {
     614             :         return [self checkKeyPress:key_def fKey_only:NO ignore_ctrl:NO];
     615             : }
     616             : 
     617             : 
     618             : - (BOOL) checkKeyPress:(NSArray*)key_def fKey_only:(BOOL)fKey_only
     619             : {
     620             :         return [self checkKeyPress:key_def fKey_only:fKey_only ignore_ctrl:NO];
     621             : }
     622             : 
     623             : 
     624             : - (BOOL) checkKeyPress:(NSArray*)key_def ignore_ctrl:(BOOL)ignore_ctrl
     625             : {
     626             :         return [self checkKeyPress:key_def fKey_only:NO ignore_ctrl:ignore_ctrl];
     627             : }
     628             : 
     629             : 
     630             : - (BOOL) checkKeyPress:(NSArray*)key_def fKey_only:(BOOL)fKey_only ignore_ctrl:(BOOL)ignore_ctrl
     631             : {
     632             :         MyOpenGLView  *gameView = [UNIVERSE gameView];
     633             :         int i;
     634             :         for (i = 0; i < [key_def count]; i++) 
     635             :         {
     636             :                 NSDictionary *def = [key_def objectAtIndex:i];
     637             :                 int keycode = [[def objectForKey:@"key"] intValue];
     638             :                 // skip normal keys if the fKey_only flag is set
     639             :                 // note: if the player has remapped the gui screen keys to not include function keys, they will not be able to 
     640             :                 // switch screens directly (they would need to finish the task - ie press enter, or use the escape key to cancel the function)
     641             :                 // note: the logic below now means that the state of the modifiers must match the requirements for the key binding, including 
     642             :                 // when all settings are off. This means, if the player presses two functions at once, one that requires a modifier and
     643             :                 // one that doesn't, the one that doesn't will not be triggered.
     644             :                 if (fKey_only == YES && (keycode < gvFunctionKey1 || keycode > gvFunctionKey11)) continue;
     645             :                 if ([gameView isDown:keycode] 
     646             :                         && ([[def objectForKey:@"shift"] boolValue] == [gameView isShiftDown])
     647             :                         && (ignore_ctrl || ([[def objectForKey:@"mod1"] boolValue] == [gameView isCtrlDown]))
     648             :                         && ([[def objectForKey:@"mod2"] boolValue] == [gameView isOptDown])
     649             :                 ) return YES;
     650             :         }
     651             :         return NO;
     652             : }
     653             : 
     654             : 
     655             : - (int) getFirstKeyCode:(NSArray*)key_def
     656             : {
     657             :         NSDictionary *def = [key_def objectAtIndex:0];
     658             :         return [[def objectForKey:@"key"] intValue];
     659             : }
     660             : 
     661             : 
     662             : - (void) pollControls:(double)delta_t
     663             : {
     664             :         MyOpenGLView  *gameView = [UNIVERSE gameView];
     665             :         NSString *exceptionContext = @"setup";
     666             :         
     667             :         @try
     668             :         {
     669             :                 if (gameView)
     670             :                 {
     671             :                         // poll the gameView keyboard things
     672             :                         exceptionContext = @"pollApplicationControls";
     673             :                         [self pollApplicationControls]; // quit command-f etc.
     674             :                         switch ([self status])
     675             :                         {
     676             :                                 case STATUS_WITCHSPACE_COUNTDOWN:
     677             :                                 case STATUS_IN_FLIGHT:
     678             :                                         exceptionContext = @"pollFlightControls";
     679             :                                         [self pollFlightControls:delta_t];
     680             :                                         break;
     681             :                                         
     682             :                                 case STATUS_DEAD:
     683             :                                         exceptionContext = @"pollGameOverControls";
     684             :                                         [self pollGameOverControls:delta_t];
     685             :                                         break;
     686             :                                         
     687             :                                 case STATUS_AUTOPILOT_ENGAGED:
     688             :                                         exceptionContext = @"pollAutopilotControls";
     689             :                                         [self pollAutopilotControls:delta_t];
     690             :                                         break;
     691             :                                         
     692             :                                 case STATUS_DOCKED:
     693             :                                         exceptionContext = @"pollDockedControls";
     694             :                                         [self pollDockedControls:delta_t];
     695             :                                         break;
     696             :                                         
     697             :                                 case STATUS_START_GAME:
     698             :                                         exceptionContext = @"pollDemoControls";
     699             :                                         [self pollDemoControls:delta_t];
     700             :                                         break;
     701             :                                         
     702             :                                 default:
     703             :                                         // don't poll extra controls at any other times.
     704             :                                         break;
     705             :                         }
     706             :                 }
     707             :         }
     708             :         @catch (NSException *exception)
     709             :         {
     710             :                 OOLog(kOOLogException, @"***** Exception checking controls [%@]: %@ : %@", exceptionContext, [exception name], [exception reason]);
     711             :         }
     712             : }
     713             : 
     714             : // DJS + aegidian: Moved from the big switch/case block in pollGuiArrowKeyControls
     715             : - (BOOL) handleGUIUpDownArrowKeys
     716             : {
     717             :         MyOpenGLView    *gameView = [UNIVERSE gameView];
     718             :         GuiDisplayGen   *gui = [UNIVERSE gui];
     719             :         BOOL                    result = NO;
     720             :         BOOL                    arrow_up = [self checkKeyPress:n_key_gui_arrow_up]; 
     721             :         BOOL                    arrow_down = [self checkKeyPress:n_key_gui_arrow_down]; 
     722             :         BOOL                    mouse_click = [gameView isDown:gvMouseLeftButton];
     723             :         BOOL                    mouse_dbl_click = [gameView isDown:gvMouseDoubleClick];
     724             : 
     725             :         if (arrow_down)
     726             :         {
     727             :                 if ((!upDownKeyPressed) || (script_time > timeLastKeyPress + KEY_REPEAT_INTERVAL))
     728             :                 {
     729             :                         if ([gui setNextRow: +1])
     730             :                         {
     731             :                                 result = YES;
     732             :                         }
     733             :                         else
     734             :                         {
     735             :                                 if ([gui setFirstSelectableRow])  result = YES;
     736             :                         }
     737             :                         
     738             :                         if (result && [gui selectableRange].length > 1)  [self playMenuNavigationDown];
     739             :                         else  [self playMenuNavigationNot];
     740             :                         
     741             :                         timeLastKeyPress = script_time;
     742             :                 }
     743             :         }
     744             :         
     745             :         if (arrow_up)
     746             :         {
     747             :                 if ((!upDownKeyPressed) || (script_time > timeLastKeyPress + KEY_REPEAT_INTERVAL))
     748             :                 {
     749             :                         if ([gui setNextRow: -1])
     750             :                         {
     751             :                                 result = YES;
     752             :                         }
     753             :                         else
     754             :                         {
     755             :                                 if ([gui setLastSelectableRow])  result = YES;
     756             :                         }
     757             :                         
     758             :                         if (result && [gui selectableRange].length > 1)  [self playMenuNavigationUp];
     759             :                         else  [self playMenuNavigationNot];
     760             : 
     761             :                         timeLastKeyPress = script_time;
     762             :                 }
     763             :         }
     764             :         
     765             :         if (mouse_click)
     766             :         {
     767             :                 if (!upDownKeyPressed)
     768             :                 {
     769             :                         int click_row = 0;
     770             :                         if (UNIVERSE)
     771             :                                 click_row = UNIVERSE->cursor_row;
     772             :                         if ([gui setSelectedRow:click_row])
     773             :                         {
     774             :                                 result = YES;
     775             :                         }
     776             :                 }
     777             :         }
     778             :         if (mouse_dbl_click)
     779             :         {
     780             :                 int click_row = 0;
     781             :                 if (UNIVERSE)
     782             :                         click_row = UNIVERSE->cursor_row;
     783             :                 if ([gui setSelectedRow:click_row])
     784             :                 {
     785             :                         result = YES;
     786             :                 }
     787             :                 else
     788             :                 {
     789             :                         // if double-clicked on an unselectable row, clear the
     790             :                         // state so it doesn't activate whatever was last
     791             :                         // selected
     792             :                         [gameView clearMouse];
     793             :                 }
     794             :         }
     795             : 
     796             :         
     797             :         upDownKeyPressed = (arrow_up || arrow_down || mouse_click);
     798             :         
     799             :         return result;
     800             : }
     801             : 
     802             : 
     803           0 : - (void) targetNewSystem:(int) direction whileTyping:(BOOL) whileTyping
     804             : {
     805             :         target_system_id = [[UNIVERSE gui] targetNextFoundSystem:direction];
     806             :         [self setInfoSystemID: target_system_id moveChart: YES];
     807             :         cursor_coordinates = [[UNIVERSE systemManager] getCoordinatesForSystem:target_system_id inGalaxy:galaxy_number];
     808             : 
     809             :         found_system_id = target_system_id;
     810             :         if (!whileTyping)
     811             :         {
     812             :                 [self clearPlanetSearchString];
     813             :         }
     814             :         cursor_moving = YES;
     815             : }
     816             : 
     817             : 
     818             : - (void) clearPlanetSearchString
     819             : {
     820             :         [[UNIVERSE gameView] resetTypedString];
     821             :         if (planetSearchString)  [planetSearchString release];
     822             :         planetSearchString = nil;
     823             : }
     824             : 
     825             : 
     826             : - (void) targetNewSystem:(int) direction
     827             : {
     828             :         [self targetNewSystem:direction whileTyping:NO];
     829             : }
     830             : 
     831             : 
     832             : - (void) switchToMainView
     833             : {
     834             :         OOGUIScreenID oldScreen = gui_screen;
     835             :         gui_screen = GUI_SCREEN_MAIN;
     836             :         if (showDemoShips)
     837             :         {
     838             :                 [self setShowDemoShips: NO];
     839             :                 [UNIVERSE removeDemoShips];
     840             :         }
     841             :         [(MyOpenGLView *)[UNIVERSE gameView] allowStringInput:NO];
     842             :         if ([self isMouseControlOn])  [[UNIVERSE gameView] resetMouse];
     843             :         [UNIVERSE enterGUIViewModeWithMouseInteraction:NO];
     844             :         [self noteGUIDidChangeFrom:oldScreen to:gui_screen];
     845             : }
     846             : 
     847             : 
     848             : - (void) noteSwitchToView:(OOViewID)toView fromView:(OOViewID)fromView
     849             : {
     850             :         [self switchToThisView:toView fromView:fromView andProcessWeaponFacing:NO justNotify:YES]; // no extra processing needed!
     851             : }
     852             : 
     853             : 
     854             : 
     855             : -(void) beginWitchspaceCountdown:(int)spin_time
     856             : {
     857             :         if ([self hasHyperspaceMotor]) 
     858             :         {
     859             :                 if (spin_time == 0) 
     860             :                 {
     861             :                         witchspaceCountdown = hyperspaceMotorSpinTime;
     862             :                 }
     863             :                 else 
     864             :                 {
     865             : #ifndef OO_DUMP_PLANETINFO
     866             :                         if (spin_time < 5) 
     867             :                         {
     868             :                                 witchspaceCountdown = 5;
     869             :                         } 
     870             :                         else 
     871             : #endif
     872             :                         {
     873             :                                 witchspaceCountdown = spin_time;
     874             :                         }
     875             :                 }
     876             :                 [self setStatus:STATUS_WITCHSPACE_COUNTDOWN];
     877             :                 [self playStandardHyperspace];
     878             :                 // say it!
     879             :                 [UNIVERSE clearPreviousMessage];
     880             :                 int seconds = round(witchspaceCountdown);
     881             :                 NSString *destination = [UNIVERSE getSystemName:[self nextHopTargetSystemID]];
     882             :                 [UNIVERSE displayCountdownMessage:OOExpandKey(@"witch-to-x-in-y-seconds", seconds, destination) forCount:1.0];
     883             :                 [self doScriptEvent:OOJSID("playerStartedJumpCountdown")
     884             :                                         withArguments:[NSArray arrayWithObjects:@"standard", [NSNumber numberWithFloat:witchspaceCountdown], nil]];
     885             :                 [UNIVERSE preloadPlanetTexturesForSystem:target_system_id];
     886             :         }
     887             : }
     888             : 
     889             : 
     890             : -(void) beginWitchspaceCountdown
     891             : {
     892             :         if ([self hasHyperspaceMotor]) {
     893             :                 [self beginWitchspaceCountdown:hyperspaceMotorSpinTime];
     894             :         }
     895             : }
     896             : 
     897             : 
     898             : -(void) cancelWitchspaceCountdown
     899             : {
     900             :         if ([self status] == STATUS_WITCHSPACE_COUNTDOWN) {
     901             :                 [self setStatus:STATUS_IN_FLIGHT];
     902             :                 [self playHyperspaceAborted];
     903             :         }
     904             :         // say it!
     905             :         [UNIVERSE clearPreviousMessage];
     906             :         [self doScriptEvent:OOJSID("playerCancelledJumpCountdown")];
     907             : }
     908             : 
     909             : @end
     910             : 
     911             : 
     912             : @implementation PlayerEntity (OOControlsPrivate)
     913             : 
     914             : - (void) pollApplicationControls
     915             : {
     916             :         if (!pollControls) return;
     917             :         
     918             :         NSString *exceptionContext = @"setup";
     919             :         
     920             :         // does fullscreen / quit / snapshot
     921             :         MyOpenGLView  *gameView = [UNIVERSE gameView];
     922             :         GameController *gameController = [UNIVERSE gameController];
     923             :         
     924             :         BOOL onTextEntryScreen = (gui_screen == GUI_SCREEN_LONG_RANGE_CHART) || (gui_screen == GUI_SCREEN_MISSION) || 
     925             :                 (gui_screen == GUI_SCREEN_SAVE) || (gui_screen == GUI_SCREEN_OXZMANAGER || (gui_screen == GUI_SCREEN_KEYBOARD_ENTRY));
     926             : 
     927             :         @try
     928             :         {
     929             :         //  command-key controls
     930             :         #if !OOLITE_MAC_OS_X || !OOLITE_64_BIT  // On 64-bit Macs, these are handled by normal menu shortcuts.
     931             :                 if ([gameController inFullScreenMode])
     932             :                 {
     933             :                         exceptionContext = @"command key controls";
     934             :                         if ([gameView isCommandFDown])
     935             :                         {
     936             :                                 [gameView clearCommandF];
     937             :                                 [gameController exitFullScreenMode];
     938             :                                 if (mouse_control_on)
     939             :                                 {
     940             :                                         [UNIVERSE addMessage:DESC(@"mouse-off") forCount:3.0];
     941             :                                         mouse_control_on = NO;
     942             :                                 }
     943             :                         }
     944             :                         
     945             :                         if ([gameView isCommandQDown])
     946             :                         {
     947             :                                 [gameController pauseFullScreenModeToPerform:@selector(exitAppCommandQ) onTarget:gameController];
     948             :                         }
     949             :                 }
     950             :         #endif
     951             :                 
     952             :                 // handle pressing Q or [esc] in error-handling mode
     953             :                 if ([self status] == STATUS_HANDLING_ERROR)
     954             :                 {
     955             :                         exceptionContext = @"error handling mode";
     956             :                         if ([gameView isDown:113]||[gameView isDown:81]||[gameView isDown:27])   // 'q' | 'Q' | esc
     957             :                         {
     958             :                                 [gameController exitAppWithContext:@"Q or escape pressed in error handling mode"];
     959             :                         }
     960             :                 }
     961             :                 
     962             :                 if ([gameController isGamePaused])
     963             :                 {
     964             :                         // What's the status?
     965             :                         switch ([self status])
     966             :                         {
     967             :                                 case STATUS_WITCHSPACE_COUNTDOWN:
     968             :                                 case STATUS_IN_FLIGHT:
     969             :                                 case STATUS_AUTOPILOT_ENGAGED:
     970             :                                 case STATUS_DOCKED:
     971             :                                         // Pause is handled inside their pollControls, no need to unpause.
     972             :                                         break;
     973             :                                         
     974             :                                 default:
     975             :                                         {
     976             :                                                 // In all other cases we can't handle pause. Unpause immediately.
     977             :                                                 script_time = saved_script_time;
     978             :                                                 [gameView allowStringInput:NO];
     979             :                                                 if ([UNIVERSE pauseMessageVisible])
     980             :                                                 {
     981             :                                                         [UNIVERSE clearPreviousMessage];        // remove the 'paused' message.
     982             :                                                 }
     983             :                                                 [gameController setGamePaused:NO];
     984             :                                         }
     985             :                                         break;
     986             :                         }
     987             :                         
     988             :                 }
     989             :                 
     990             :                 // snapshot
     991             :                 const BOOL *joyButtonState = [[OOJoystickManager sharedStickHandler] getAllButtonStates];
     992             : 
     993             :                 if (([self checkKeyPress:n_key_snapshot] || joyButtonState[BUTTON_SNAPSHOT]) &&
     994             :                         ([gameView allowingStringInput] <= gvStringInputAlpha) && // not while entering text on the keyboard config screens
     995             :                         ![[OOOXZManager sharedManager] isAcceptingTextInput])   //  '*' key but not while filtering inside OXZ Manager
     996             :                 {
     997             :                         exceptionContext = @"snapshot";
     998             :                         if (!taking_snapshot)
     999             :                         {
    1000             :                                 taking_snapshot = YES;
    1001             :                                 [gameView snapShot:nil]; // nil filename so that the program auto-names the snapshot
    1002             :                         }
    1003             :                 }
    1004             :                 else
    1005             :                 {
    1006             :                         taking_snapshot = NO;
    1007             :                 }
    1008             :                 
    1009             :                 // FPS display
    1010             :                 if (!onTextEntryScreen && [self checkKeyPress:n_key_show_fps])   //  'F' key
    1011             :                 {
    1012             :                         exceptionContext = @"toggle FPS";
    1013             :                         if (!f_key_pressed)  [UNIVERSE setDisplayFPS:![UNIVERSE displayFPS]];
    1014             :                         f_key_pressed = YES;
    1015             :                 }
    1016             :                 else
    1017             :                 {
    1018             :                         f_key_pressed = NO;
    1019             :                 }
    1020             :                 
    1021             :                 // bloom toggle
    1022             :                 if ([self checkKeyPress:n_key_bloom_toggle])
    1023             :                 {
    1024             :                         if (!f9_key_pressed)
    1025             :                         {
    1026             :                                 BOOL oldBloom = [UNIVERSE bloom];
    1027             :                                 [UNIVERSE setBloom:!oldBloom];
    1028             :                         }
    1029             :                         f9_key_pressed = YES;
    1030             :                 }
    1031             :                 else
    1032             :                 {
    1033             :                         f9_key_pressed = NO;
    1034             :                 }
    1035             :                 
    1036             :                 // Mouse control
    1037             :                 BOOL allowMouseControl;
    1038             :         #if OO_DEBUG
    1039             :                 allowMouseControl = YES;
    1040             :         #else
    1041             :                 allowMouseControl = [gameController inFullScreenMode] ||
    1042             :                                         [[NSUserDefaults standardUserDefaults] boolForKey:@"mouse-control-in-windowed-mode"];
    1043             :         #endif
    1044             :                 
    1045             :                 if (allowMouseControl)
    1046             :                 {
    1047             :                         exceptionContext = @"mouse control";
    1048             :                         if (!onTextEntryScreen && ([self checkKeyPress:n_key_mouse_control_roll] || [self checkKeyPress:n_key_mouse_control_yaw]))   //  'M' key
    1049             :                         {
    1050             :                                 if (!m_key_pressed)
    1051             :                                 {
    1052             :                                         mouse_control_on = !mouse_control_on;
    1053             :                                         if (mouse_control_on)
    1054             :                                         {
    1055             :                                                 [UNIVERSE addMessage:DESC(@"mouse-on") forCount:3.0];
    1056             :                                                 /*      Ensure the keyboard pitch override (intended to lock
    1057             :                                                  out the joystick if the player runs to the keyboard)
    1058             :                                                  is reset */
    1059             :                                         #if OOLITE_GNUSTEP
    1060             :                                                 [gameView resetMouse];
    1061             :                                                 if ([[NSUserDefaults standardUserDefaults] boolForKey:@"grab-mouse-on-mouse-control"])
    1062             :                                                 {
    1063             :                                                         [gameView grabMouseInsideGameWindow:YES];
    1064             :                                                 }
    1065             :                                         #endif
    1066             :                                                 mouse_x_axis_map_to_yaw = [self checkKeyPress:n_key_mouse_control_yaw];
    1067             :                                                 keyboardRollOverride = mouse_x_axis_map_to_yaw;   // Getafix: set keyboardRollOverride to TRUE only if yaw is mapped to mouse x-axis
    1068             :                                                 keyboardPitchOverride = NO;
    1069             :                                                 keyboardYawOverride = !keyboardRollOverride;
    1070             :                                         }
    1071             :                                         else
    1072             :                                         {
    1073             :                                                 [UNIVERSE addMessage:DESC(@"mouse-off") forCount:3.0];
    1074             :                     #if OOLITE_GNUSTEP
    1075             :                                                 [gameView grabMouseInsideGameWindow:NO];
    1076             :                     #endif
    1077             :                                         }
    1078             :                                 }
    1079             :                                 if (OOMouseInteractionModeIsFlightMode([gameController mouseInteractionMode]))
    1080             :                                 {
    1081             :                                         [gameController setMouseInteractionModeForFlight];
    1082             :                                 }
    1083             :                                 m_key_pressed = YES;
    1084             :                         }
    1085             :                         else
    1086             :                         {
    1087             :                                 m_key_pressed = NO;
    1088             :                         }
    1089             :                 }
    1090             :                 else
    1091             :                 {
    1092             :                         if (mouse_control_on)
    1093             :                         {
    1094             :                                 mouse_control_on = NO;
    1095             :                                 [UNIVERSE addMessage:DESC(@"mouse-off") forCount:3.0];
    1096             :             #if OOLITE_GNUSTEP
    1097             :                                 [gameView grabMouseInsideGameWindow:NO];
    1098             :             #endif
    1099             :                                 
    1100             :                                 if (OOMouseInteractionModeIsFlightMode([gameController mouseInteractionMode]))
    1101             :                                 {
    1102             :                                         [gameController setMouseInteractionModeForFlight];
    1103             :                                 }
    1104             :                         }
    1105             :                 }
    1106             :                 
    1107             :                 // HUD toggle
    1108             :                 if (([self checkKeyPress:n_key_hud_toggle] || joyButtonState[BUTTON_TOGGLEHUD]) && [gameController isGamePaused] && !onTextEntryScreen) // 'o' key while paused
    1109             :                 {
    1110             :                         exceptionContext = @"toggle HUD";
    1111             :                         if (!hide_hud_pressed)
    1112             :                         {
    1113             :                                 HeadUpDisplay *theHUD = [self hud];
    1114             :                                 [theHUD setHidden:![theHUD isHidden]];
    1115             :                                 if (gui_screen == GUI_SCREEN_STATUS)
    1116             :                                 {
    1117             :                                         // ensure refresh of status page screen if looking at it
    1118             :                                         [self setGuiToStatusScreen];
    1119             :                                 }
    1120             :                         }
    1121             :                         hide_hud_pressed = YES;
    1122             :                 }
    1123             :                 else
    1124             :                 {
    1125             :                         hide_hud_pressed = NO;
    1126             :                 }
    1127             :         }
    1128             :         @catch (NSException *exception)
    1129             :         {
    1130             :                 OOLog(kOOLogException, @"***** Exception in pollApplicationControls [%@]: %@ : %@", exceptionContext, [exception name], [exception reason]);
    1131             :         }
    1132             : }
    1133             : 
    1134             : 
    1135             : - (void) pollFlightControls:(double)delta_t
    1136             : {
    1137             :         MyOpenGLView            *gameView = [UNIVERSE gameView];
    1138             :         OOJoystickManager       *stickHandler = [OOJoystickManager sharedStickHandler];
    1139             :         NSString                        *exceptionContext = @"setup";
    1140             : 
    1141             :         @try
    1142             :         {
    1143             :                 exceptionContext = @"joystick handling";
    1144             :                 const BOOL *joyButtonState = [[OOJoystickManager sharedStickHandler] getAllButtonStates];
    1145             :                 
    1146             :                 BOOL paused = [[UNIVERSE gameController] isGamePaused];
    1147             :                 double speed_delta = SHIP_THRUST_FACTOR * thrust;
    1148             :                 
    1149             :                 if (!paused && gui_screen == GUI_SCREEN_MISSION)
    1150             :                 {
    1151             :                         exceptionContext = @"mission screen";
    1152             :                         OOViewID view = VIEW_NONE;
    1153             :                         
    1154             :                         NSPoint                 virtualView = NSZeroPoint;
    1155             :                         double                  view_threshold = 0.5;
    1156             :                         
    1157             :                         if ([stickHandler joystickCount])
    1158             :                         {
    1159             :                                 virtualView = [stickHandler viewAxis];
    1160             :                                 if (virtualView.y == STICK_AXISUNASSIGNED)
    1161             :                                         virtualView.y = 0.0;
    1162             :                                 if (virtualView.x == STICK_AXISUNASSIGNED)
    1163             :                                         virtualView.x = 0.0;
    1164             :                                 if (fabs(virtualView.y) >= fabs(virtualView.x))
    1165             :                                         virtualView.x = 0.0; // forward/aft takes precedence
    1166             :                                 else
    1167             :                                         virtualView.y = 0.0;
    1168             :                         }
    1169             :                 
    1170             :                         if ([self checkKeyPress:n_key_view_forward] || (virtualView.y < -view_threshold) || joyButtonState[BUTTON_VIEWFORWARD])
    1171             :                         {
    1172             :                                 view = VIEW_FORWARD;
    1173             :                         }
    1174             :                         if ([self checkKeyPress:n_key_view_aft]|(virtualView.y > view_threshold)||joyButtonState[BUTTON_VIEWAFT])
    1175             :                         {
    1176             :                                 view = VIEW_AFT;
    1177             :                         }
    1178             :                         if ([self checkKeyPress:n_key_view_port]||(virtualView.x < -view_threshold)||joyButtonState[BUTTON_VIEWPORT])
    1179             :                         {
    1180             :                                 view = VIEW_PORT;
    1181             :                         }
    1182             :                         if ([self checkKeyPress:n_key_view_starboard]||(virtualView.x > view_threshold)||joyButtonState[BUTTON_VIEWSTARBOARD])
    1183             :                         {
    1184             :                                 view = VIEW_STARBOARD;
    1185             :                         }
    1186             :                         if (view == VIEW_NONE)
    1187             :                         {
    1188             :                                 // still in mission screen, process the input.
    1189             :                                 [self pollDemoControls: delta_t];
    1190             :                         }
    1191             :                         else
    1192             :                         {
    1193             :                                 [[UNIVERSE gui] clearBackground];
    1194             :                                 [self switchToThisView:view];
    1195             :                                 if (_missionWithCallback)
    1196             :                                 {
    1197             :                                         [self doMissionCallback];
    1198             :                                 }
    1199             :                                 // notify older scripts, but do not trigger missionScreenOpportunity.
    1200             :                                 [self doWorldEventUntilMissionScreen:OOJSID("missionScreenEnded")];
    1201             :                         }
    1202             :                 }
    1203             :                 else if (!paused)
    1204             :                 {
    1205             :                         exceptionContext = @"arrow keys";
    1206             :                         // arrow keys
    1207             :                         if ([UNIVERSE displayGUI])
    1208             :                                 [self pollGuiArrowKeyControls:delta_t];
    1209             :                         else
    1210             :                                 [self pollFlightArrowKeyControls:delta_t];
    1211             :                         
    1212             :                         //  view keys
    1213             :                         [self pollViewControls];
    1214             :                         
    1215             :                         if (OOMouseInteractionModeIsFlightMode([[UNIVERSE gameController] mouseInteractionMode]))
    1216             :                         {
    1217             :                                 exceptionContext = @"afterburner";
    1218             :                                 if ((joyButtonState[BUTTON_FUELINJECT] || [self checkKeyPress:n_key_inject_fuel]) &&
    1219             :                                         [self hasFuelInjection] &&
    1220             :                                         !hyperspeed_engaged)
    1221             :                                 {
    1222             :                                         if (fuel > 0 && !afterburner_engaged)
    1223             :                                         {
    1224             :                                                 [UNIVERSE addMessage:DESC(@"fuel-inject-on") forCount:1.5];
    1225             :                                                 afterburner_engaged = YES;
    1226             :                                                 [self startAfterburnerSound];
    1227             :                                         }
    1228             :                                         else
    1229             :                                         {
    1230             :                                                 if (fuel <= 0.0)
    1231             :                                                         [UNIVERSE addMessage:DESC(@"fuel-out") forCount:1.5];
    1232             :                                         }
    1233             :                                         afterburner_engaged = (fuel > 0);
    1234             :                                 }
    1235             :                                 else
    1236             :                                         afterburner_engaged = NO;
    1237             :                                 
    1238             :                                 if ((!afterburner_engaged)&&(afterburnerSoundLooping))
    1239             :                                         [self stopAfterburnerSound];
    1240             :                                 
    1241             :                                 exceptionContext = @"thrust";
    1242             :                                 // DJS: Thrust can be an axis or a button. Axis takes precidence.
    1243             :                                 double reqSpeed=[stickHandler getAxisState: AXIS_THRUST];
    1244             :                                 float mouseWheelDeltaFactor = mouse_control_on ? fabs([gameView mouseWheelDelta]) : 1.0f;
    1245             :                                 if (mouseWheelDeltaFactor == 0.0f)  mouseWheelDeltaFactor = 1.0f;
    1246             :                                 // Updated DJS original code to fix BUG #17482 - (Getafix 2010/09/13)
    1247             :                                 if (([self checkKeyPress:n_key_increase_speed] ||
    1248             :                                                 joyButtonState[BUTTON_INCTHRUST] ||
    1249             :                                                  ((mouse_control_on)&&([gameView mouseWheelState] == gvMouseWheelUp) && ([UNIVERSE viewDirection] <= VIEW_STARBOARD || ![gameView isCapsLockOn])))
    1250             :                                         && (flightSpeed < maxFlightSpeed) && (!afterburner_engaged))
    1251             :                                 {
    1252             :                                         flightSpeed += speed_delta * delta_t * mouseWheelDeltaFactor;
    1253             :                                 }
    1254             :                                 
    1255             :                                 if (([self checkKeyPress:n_key_decrease_speed] ||
    1256             :                                                 joyButtonState[BUTTON_DECTHRUST] ||
    1257             :                                                 ((mouse_control_on)&&([gameView mouseWheelState] == gvMouseWheelDown) && ([UNIVERSE viewDirection] <= VIEW_STARBOARD || ![gameView isCapsLockOn])))
    1258             :                                         && (!afterburner_engaged))
    1259             :                                 {
    1260             :                                         flightSpeed -= speed_delta * delta_t * mouseWheelDeltaFactor;   
    1261             :                                         // ** tgape ** - decrease obviously means no hyperspeed
    1262             :                                         hyperspeed_engaged = NO;
    1263             :                                 }
    1264             : 
    1265             :                                 NSDictionary *functionForThrustAxis = [[stickHandler axisFunctions] oo_dictionaryForKey:[[NSNumber numberWithInt:AXIS_THRUST] stringValue]];
    1266             :                                 if([stickHandler joystickCount] != 0 && functionForThrustAxis != nil)
    1267             :                                 {
    1268             :                                         if (flightSpeed < maxFlightSpeed * reqSpeed)
    1269             :                                         {
    1270             :                                                 flightSpeed += speed_delta * delta_t;
    1271             :                                         }
    1272             :                                         if (flightSpeed > maxFlightSpeed * reqSpeed)
    1273             :                                         {
    1274             :                                                 flightSpeed -= speed_delta * delta_t;
    1275             :                                         }
    1276             :                                 } // DJS: end joystick thrust axis (Getafix - End code update for fixing BUG #17482)
    1277             :                                 
    1278             :                                 if (!afterburner_engaged && ![self atHyperspeed] && !hyperspeed_engaged)
    1279             :                                 {
    1280             :                                         flightSpeed = OOClamp_0_max_f(flightSpeed, maxFlightSpeed);
    1281             :                                 }
    1282             :                                 
    1283             :                                 exceptionContext = @"hyperspeed";
    1284             :                                 //  hyperspeed controls
    1285             :                                 if ([self checkKeyPress:n_key_jumpdrive] || joyButtonState[BUTTON_HYPERSPEED])          // 'j'
    1286             :                                 {
    1287             :                                         if (!jump_pressed)
    1288             :                                         {
    1289             :                                                 if (!hyperspeed_engaged)
    1290             :                                                 {
    1291             :                                                         hyperspeed_locked = [self massLocked];
    1292             :                                                         hyperspeed_engaged = !hyperspeed_locked;
    1293             :                                                         if (hyperspeed_locked)
    1294             :                                                         {
    1295             :                                                                 [self playJumpMassLocked];
    1296             :                                                                 [UNIVERSE addMessage:DESC(@"jump-mass-locked") forCount:1.5];
    1297             :                                                         }
    1298             :                                                 }
    1299             :                                                 else
    1300             :                                                 {
    1301             :                                                         hyperspeed_engaged = NO;
    1302             :                                                 }
    1303             :                                         }
    1304             :                                         jump_pressed = YES;
    1305             :                                 }
    1306             :                                 else
    1307             :                                 {
    1308             :                                         jump_pressed = NO;
    1309             :                                 }
    1310             :                                 
    1311             :                                 exceptionContext = @"shoot";
    1312             :                                 //  shoot 'a'
    1313             :                                 if ((([self checkNavKeyPress:n_key_fire_lasers])||((mouse_control_on)&&([gameView isDown:gvMouseLeftButton]) && ([UNIVERSE viewDirection] <= VIEW_STARBOARD || ![gameView isCapsLockOn]))||joyButtonState[BUTTON_FIRE])&&(shot_time > weapon_recharge_rate))
    1314             :                                 {
    1315             :                                         if ([self fireMainWeapon])
    1316             :                                         {
    1317             :                                                 [self playLaserHit:([self shipHitByLaser] != nil) offset:[[self currentLaserOffset] oo_vectorAtIndex:0] weaponIdentifier:[[self currentWeapon] identifier]];
    1318             :                                         }
    1319             :                                 }
    1320             :                                 
    1321             :                                 exceptionContext = @"weapons online toggle";
    1322             :                                 // weapons online / offline toggle '_'
    1323             :                                 if (([self checkKeyPress:n_key_weapons_online_toggle] || joyButtonState[BUTTON_WEAPONSONLINETOGGLE]))
    1324             :                                 {
    1325             :                                         if (!weaponsOnlineToggle_pressed)
    1326             :                                         {
    1327             :                                                 NSString*       weaponsOnlineToggleMsg;
    1328             :                                                 
    1329             :                                                 [self setWeaponsOnline:![self weaponsOnline]];
    1330             :                                                 weaponsOnlineToggleMsg = [self weaponsOnline] ? DESC(@"weapons-systems-online") : DESC(@"weapons-systems-offline");
    1331             :                                                 if ([self weaponsOnline])
    1332             :                                                 {
    1333             :                                                         [self playWeaponsOnline];
    1334             :                                                 }
    1335             :                                                 else
    1336             :                                                 {
    1337             :                                                         [self playWeaponsOffline];
    1338             :                                                 }
    1339             :                                                 [UNIVERSE addMessage:weaponsOnlineToggleMsg forCount:2.0];
    1340             :                                                 [self doScriptEvent:OOJSID("weaponsSystemsToggled") withArgument:[NSNumber numberWithBool:[self weaponsOnline]]];
    1341             :                                                 weaponsOnlineToggle_pressed = YES;
    1342             :                                         }
    1343             :                                 }
    1344             :                                 else  weaponsOnlineToggle_pressed = NO;
    1345             :                                 
    1346             :                                 exceptionContext = @"missile fire";
    1347             :                                 //  shoot 'm'   // launch missile
    1348             :                                 if ([self checkKeyPress:n_key_launch_missile] || joyButtonState[BUTTON_LAUNCHMISSILE])
    1349             :                                 {
    1350             :                                         // launch here
    1351             :                                         if (!fire_missile_pressed)
    1352             :                                         {
    1353             :                                                 [self fireMissile];
    1354             :                                                 fire_missile_pressed = YES;
    1355             :                                         }
    1356             :                                 }
    1357             :                                 else  fire_missile_pressed = NO;
    1358             :                                 
    1359             :                                 exceptionContext = @"next missile";
    1360             :                                 //  shoot 'y'   // next missile
    1361             :                                 if ([self checkKeyPress:n_key_next_missile] || joyButtonState[BUTTON_CYCLEMISSILE])
    1362             :                                 {
    1363             :                                         if (!ident_engaged && !next_missile_pressed && [self weaponsOnline])
    1364             :                                         {
    1365             :                                                 [self playNextMissileSelected];
    1366             :                                                 [self selectNextMissile];
    1367             :                                         }
    1368             :                                         next_missile_pressed = YES;
    1369             :                                 }
    1370             :                                 else  next_missile_pressed = NO;
    1371             :                                 
    1372             :                                 exceptionContext = @"next target";
    1373             :                                 //      '+' // next target
    1374             :                                 if ([self checkKeyPress:n_key_next_target] || joyButtonState[BUTTON_NEXTTARGET])
    1375             :                                 {
    1376             :                                         if ((!next_target_pressed)&&([self hasEquipmentItemProviding:@"EQ_TARGET_MEMORY"]))
    1377             :                                         {
    1378             :                                                 [self moveTargetMemoryBy:+1];
    1379             :                                         }
    1380             :                                         next_target_pressed = YES;
    1381             :                                 }
    1382             :                                 else  next_target_pressed = NO;
    1383             :                                 
    1384             :                                 exceptionContext = @"previous target";
    1385             :                                 //      '-' // previous target
    1386             :                                 if ([self checkKeyPress:n_key_previous_target] || joyButtonState[BUTTON_PREVTARGET])
    1387             :                                 {
    1388             :                                         if ((!previous_target_pressed)&&([self hasEquipmentItemProviding:@"EQ_TARGET_MEMORY"]))
    1389             :                                         {
    1390             :                                                 [self moveTargetMemoryBy:-1];
    1391             :                                         }
    1392             :                                         previous_target_pressed = YES;
    1393             :                                 }
    1394             :                                 else  previous_target_pressed = NO;
    1395             :                                 
    1396             :                                 exceptionContext = @"ident R";
    1397             :                                 //  shoot 'r'   // switch on ident system
    1398             :                                 if ([self checkKeyPress:n_key_ident_system] || joyButtonState[BUTTON_ID])
    1399             :                                 {
    1400             :                                         // ident 'on' here
    1401             :                                         if (!ident_pressed)
    1402             :                                         {
    1403             :                                                 [self handleButtonIdent];
    1404             :                                         }
    1405             :                                         ident_pressed = YES;
    1406             :                                 }
    1407             :                                 else  ident_pressed = NO;
    1408             :                                 
    1409             :                                 exceptionContext = @"prime equipment";
    1410             :                                 // prime equipment 'N' - selects equipment to use with keypress
    1411             :                                 if ([self checkKeyPress:n_key_prime_next_equipment] || [self checkKeyPress:n_key_prime_previous_equipment] || joyButtonState[BUTTON_PRIMEEQUIPMENT] || joyButtonState[BUTTON_PRIMEEQUIPMENT_PREV])
    1412             :                                 {
    1413             : 
    1414             :                                         if (!prime_equipment_pressed)
    1415             :                                         {
    1416             : 
    1417             :                                                 // cycle through all the relevant equipment.
    1418             :                                                 NSUInteger c = [eqScripts count];
    1419             :                                                 
    1420             :                                                 // if Ctrl is held down at the same time as the prime equipment key,
    1421             :                                                 // cycle relevant equipment in reverse
    1422             :                                                 //if (![gameView isCtrlDown])
    1423             :                                                 if (![self checkKeyPress:n_key_prime_previous_equipment] || joyButtonState[BUTTON_PRIMEEQUIPMENT_PREV])
    1424             :                                                 {
    1425             :                                                         primedEquipment++;
    1426             :                                                         if (primedEquipment > c) primedEquipment = 0;
    1427             :                                                 }
    1428             :                                                 else
    1429             :                                                 {
    1430             :                                                         if (primedEquipment > 0)  primedEquipment--;
    1431             :                                                         else  primedEquipment = c;
    1432             :                                                 }
    1433             :                                                 
    1434             :                                                 NSString *eqKey = @"";
    1435             : 
    1436             :                                                 if (primedEquipment == c)
    1437             :                                                 {
    1438             :                                                         if (c > 0)
    1439             :                                                         {
    1440             :                                                                 [self playNextEquipmentSelected];
    1441             :                                                                 [UNIVERSE addMessage:DESC(@"equipment-primed-none") forCount:2.0];
    1442             :                                                         }
    1443             :                                                         else [UNIVERSE addMessage:DESC(@"equipment-primed-none-available") forCount:2.0];
    1444             :                                                 }
    1445             :                                                 else
    1446             :                                                 {
    1447             :                                                         [self playNextEquipmentSelected];
    1448             :                                                         NSString *equipmentName = [[OOEquipmentType equipmentTypeWithIdentifier:[[eqScripts oo_arrayAtIndex:primedEquipment] oo_stringAtIndex:0]] name];
    1449             :                                                         eqKey = [[eqScripts oo_arrayAtIndex:primedEquipment] oo_stringAtIndex:0];
    1450             :                                                         [UNIVERSE addMessage:OOExpandKey(@"equipment-primed", equipmentName) forCount:2.0];
    1451             :                                                 }
    1452             :                                                 [self doScriptEvent:OOJSID("playerChangedPrimedEquipment") withArgument:eqKey];
    1453             :                                         }
    1454             :                                         prime_equipment_pressed = YES;
    1455             :                                         
    1456             :                                 }
    1457             :                                 else  prime_equipment_pressed = NO;
    1458             :                                 
    1459             :                                 exceptionContext = @"activate equipment";
    1460             :                                 // activate equipment 'n' - runs the activated() function inside the equipment's script.
    1461             :                                 if ([self checkKeyPress:n_key_activate_equipment] || joyButtonState[BUTTON_ACTIVATEEQUIPMENT])
    1462             :                                 {
    1463             :                                         if (!activate_equipment_pressed)
    1464             :                                         {
    1465             :                                                 [self activatePrimableEquipment:primedEquipment withMode:OOPRIMEDEQUIP_ACTIVATED];
    1466             :                                         }
    1467             :                                         activate_equipment_pressed = YES;
    1468             :                                 }
    1469             :                                 else  activate_equipment_pressed = NO;
    1470             :                                 
    1471             :                                 exceptionContext = @"mode equipment";
    1472             :                                 // mode equipment 'b' - runs the mode() function inside the equipment's script.
    1473             :                                 if ([self checkKeyPress:n_key_mode_equipment] || joyButtonState[BUTTON_MODEEQUIPMENT])
    1474             :                                 {
    1475             :                                         if (!mode_equipment_pressed)
    1476             :                                         {
    1477             :                                                 [self activatePrimableEquipment:primedEquipment withMode:OOPRIMEDEQUIP_MODE];
    1478             :                                         }
    1479             :                                         mode_equipment_pressed = YES;
    1480             :                                 }
    1481             :                                 else  mode_equipment_pressed = NO;
    1482             : 
    1483             :                                 exceptionContext = @"fast equipment A";
    1484             :                                 if ([self checkKeyPress:n_key_fastactivate_equipment_a] || joyButtonState[BUTTON_CLOAK])
    1485             :                                 {
    1486             :                                         if (!fastactivate_a_pressed)
    1487             :                                         {
    1488             :                                                 [self activatePrimableEquipment:[self eqScriptIndexForKey:[self fastEquipmentA]] withMode:OOPRIMEDEQUIP_ACTIVATED];
    1489             :                                         }
    1490             :                                         fastactivate_a_pressed = YES;
    1491             :                                 }
    1492             :                                 else fastactivate_a_pressed = NO;
    1493             : 
    1494             :                                 exceptionContext = @"fast equipment B";
    1495             :                                 if ([self checkKeyPress:n_key_fastactivate_equipment_b] || joyButtonState[BUTTON_ENERGYBOMB])
    1496             :                                 {
    1497             :                                         if (!fastactivate_b_pressed)
    1498             :                                         {
    1499             :                                                 [self activatePrimableEquipment:[self eqScriptIndexForKey:[self fastEquipmentB]] withMode:OOPRIMEDEQUIP_ACTIVATED];
    1500             :                                         }
    1501             :                                         fastactivate_b_pressed = YES;
    1502             :                                 }
    1503             :                                 else fastactivate_b_pressed = NO;
    1504             : 
    1505             :                                 exceptionContext = @"custom equipment";
    1506             :                                 // loop through all the objects in the customEquipActivation array
    1507             :                                 NSDictionary *item;
    1508             :                                 NSUInteger i;
    1509             :                                 for (i = 0; i < [customEquipActivation count]; i++)
    1510             :                                 {
    1511             :                                         item = [customEquipActivation objectAtIndex:i];
    1512             :                                         // check if the player has the equip item installed
    1513             :                                         if ([self hasOneEquipmentItem:[item oo_stringForKey:CUSTOMEQUIP_EQUIPKEY] includeWeapons:NO whileLoading:NO])
    1514             :                                         {
    1515             :                                                 NSArray *key_act = [item oo_arrayForKey:CUSTOMEQUIP_KEYACTIVATE];
    1516             :                                                 NSArray *key_mod = [item oo_arrayForKey:CUSTOMEQUIP_KEYMODE];
    1517             :                                                 NSDictionary *but_act = [item oo_dictionaryForKey:CUSTOMEQUIP_BUTTONACTIVATE];
    1518             :                                                 NSDictionary *but_mod = [item oo_dictionaryForKey:CUSTOMEQUIP_BUTTONMODE];
    1519             :                                                 // if so, 
    1520             :                                                 // check to see if the key or button was pressed for activate
    1521             :                                                 if ((key_act && [self checkKeyPress:key_act]) || (but_act && [[OOJoystickManager sharedStickHandler] isButtonDown:[but_act oo_intForKey:STICK_AXBUT] stick:[but_act oo_intForKey:STICK_NUMBER]]))
    1522             :                                                 {
    1523             :                                                         if (![[customActivatePressed objectAtIndex:i] boolValue])
    1524             :                                                         {
    1525             :                                                                 // initate the activate JS code
    1526             :                                                                 [self activatePrimableEquipment:[self eqScriptIndexForKey:[item oo_stringForKey:CUSTOMEQUIP_EQUIPKEY]] withMode:OOPRIMEDEQUIP_ACTIVATED];
    1527             :                                                         }
    1528             :                                                         [customActivatePressed replaceObjectAtIndex:i withObject:[NSNumber numberWithBool:YES]];
    1529             :                                                 }
    1530             :                                                 else [customActivatePressed replaceObjectAtIndex:i withObject:[NSNumber numberWithBool:NO]];
    1531             : 
    1532             :                                                 // check to see if the key or button was pressed for mode
    1533             :                                                 if ((key_mod && [self checkKeyPress:key_mod]) || (but_mod && [[OOJoystickManager sharedStickHandler] isButtonDown:[but_mod oo_intForKey:STICK_AXBUT] stick:[but_mod oo_intForKey:STICK_NUMBER]]))
    1534             :                                                 {
    1535             :                                                         if (![[customModePressed objectAtIndex:i] boolValue])
    1536             :                                                         {
    1537             :                                                                 // initiate the activate JS code
    1538             :                                                                 [self activatePrimableEquipment:[self eqScriptIndexForKey:[item oo_stringForKey:CUSTOMEQUIP_EQUIPKEY]] withMode:OOPRIMEDEQUIP_MODE];
    1539             :                                                         }
    1540             :                                                         [customModePressed replaceObjectAtIndex:i withObject:[NSNumber numberWithBool:YES]];
    1541             :                                                 }
    1542             :                                                 else [customModePressed replaceObjectAtIndex:i withObject:[NSNumber numberWithBool:NO]];
    1543             :                                         }
    1544             :                                 }
    1545             : 
    1546             :                                 exceptionContext = @"incoming missile T";
    1547             :                                 // target nearest incoming missile 'T' - useful for quickly giving a missile target to turrets
    1548             :                                 if ([self checkKeyPress:n_key_target_incoming_missile] || joyButtonState[BUTTON_TARGETINCOMINGMISSILE])
    1549             :                                 {
    1550             :                                         if (!target_incoming_missile_pressed)
    1551             :                                         {
    1552             :                                                 [self targetNearestIncomingMissile];
    1553             :                                         }
    1554             :                                         target_incoming_missile_pressed = YES;
    1555             :                                 }
    1556             :                                 else  target_incoming_missile_pressed = NO;
    1557             :                                 
    1558             :                                 exceptionContext = @"missile T";
    1559             :                                 //  shoot 't'   // switch on missile targeting
    1560             :                                 if (([self checkKeyPress:n_key_target_missile] || joyButtonState[BUTTON_ARMMISSILE])&&(missile_entity[activeMissile]))
    1561             :                                 {
    1562             :                                         // targeting 'on' here
    1563             :                                         if (!target_missile_pressed)
    1564             :                                         {
    1565             :                                                 [self handleButtonTargetMissile];
    1566             :                                         }
    1567             :                                         target_missile_pressed = YES;
    1568             :                                 }
    1569             :                                 else  target_missile_pressed = NO;
    1570             :                                 
    1571             :                                 exceptionContext = @"missile U";
    1572             :                                 //  shoot 'u'   // disarm missile targeting
    1573             :                                 if ([self checkKeyPress:n_key_untarget_missile] || joyButtonState[BUTTON_UNARM])
    1574             :                                 {
    1575             :                                         if (!safety_pressed)
    1576             :                                         {
    1577             :                                                 //targeting off in both cases!
    1578             :                                                 if ([self primaryTarget] != nil) [self noteLostTarget];
    1579             :                                                 DESTROY(_primaryTarget);
    1580             :                                                 [self safeAllMissiles];
    1581             :                                                 if (!ident_engaged && [self weaponsOnline])
    1582             :                                                 {
    1583             :                                                         [UNIVERSE addMessage:DESC(@"missile-safe") forCount:2.0];
    1584             :                                                         [self playMissileSafe];
    1585             :                                                 }
    1586             :                                                 else
    1587             :                                                 {
    1588             :                                                         [UNIVERSE addMessage:DESC(@"ident-off") forCount:2.0];
    1589             :                                                         [self playIdentOff];
    1590             :                                                 }
    1591             :                                                 ident_engaged = NO;
    1592             :                                         }
    1593             :                                         safety_pressed = YES;
    1594             :                                 }
    1595             :                                 else  safety_pressed = NO;
    1596             :                                 
    1597             :                                 exceptionContext = @"ECM";
    1598             :                                 //  shoot 'e'   // ECM
    1599             :                                 if (([self checkKeyPress:n_key_ecm] || joyButtonState[BUTTON_ECM]) && [self hasECM])
    1600             :                                 {
    1601             :                                         if (!ecm_in_operation)
    1602             :                                         {
    1603             :                                                 if ([self fireECM])
    1604             :                                                 {
    1605             :                                                         [self playFiredECMSound];
    1606             :                                                         [UNIVERSE addMessage:DESC(@"ecm-on") forCount:3.0];
    1607             :                                                 }
    1608             :                                         }
    1609             :                                 }
    1610             :                                 
    1611             :                         
    1612             :                                 exceptionContext = @"escape pod";
    1613             :                                 //  shoot 'escape'   // Escape pod launch - NOTE: Allowed at all times, but requires double press within a specific time interval.
    1614             :                                                         // Double press not available in strict mode or when the "escape-pod-activation-immediate" override is in the 
    1615             :                                                         // user defaults file.
    1616             :                                 if (([self checkKeyPress:n_key_launch_escapepod] || joyButtonState[BUTTON_ESCAPE]) && [self hasEscapePod])
    1617             :                                 {
    1618             :                                         BOOL    goodToLaunch = [[NSUserDefaults standardUserDefaults] boolForKey:@"escape-pod-activation-immediate"];
    1619             :                                         static  OOTimeDelta     escapePodKeyResetTime;
    1620             :                                         
    1621             :                                         if (!goodToLaunch)
    1622             :                                         {
    1623             :                                                 if (!escapePodKey_pressed)
    1624             :                                                 {
    1625             :                                                         escapePodKey_pressed = YES;
    1626             :                                                         // first keypress will unregister in KEY_REPEAT_INTERVAL seconds
    1627             :                                                         escapePodKeyResetTime = [NSDate timeIntervalSinceReferenceDate] + KEY_REPEAT_INTERVAL;
    1628             :                                                         //[gameView clearKey:key_launch_escapepod];
    1629             :                                                         [gameView clearKey:[self getFirstKeyCode:n_key_launch_escapepod]];
    1630             :                                                         if ([stickHandler joystickCount])
    1631             :                                                         {
    1632             :                                                                 [stickHandler clearStickButtonState:BUTTON_ESCAPE];
    1633             :                                                         }
    1634             :                                                 }
    1635             :                                                 else
    1636             :                                                 {
    1637             :                                                         OOTimeDelta timeNow = [NSDate timeIntervalSinceReferenceDate];
    1638             :                                                         escapePodKey_pressed = NO;
    1639             :                                                         if (timeNow < escapePodKeyResetTime)  goodToLaunch = YES;
    1640             :                                                 }
    1641             :                                         }
    1642             :                                         if (goodToLaunch)
    1643             :                                         {
    1644             :                                                 [self launchEscapeCapsule];
    1645             :                                         }
    1646             :                                 }
    1647             :                                 
    1648             :                                 exceptionContext = @"dump cargo";
    1649             :                                 //  shoot 'd'   // Dump Cargo
    1650             :                                 if (([self checkKeyPress:n_key_dump_cargo] || joyButtonState[BUTTON_JETTISON]) && [cargo count] > 0)
    1651             :                                 {
    1652             :                                         [self dumpCargo];
    1653             :                                 }
    1654             :                                 
    1655             :                                 exceptionContext = @"rotate cargo";
    1656             :                                 //  shoot 'R'   // Rotate Cargo
    1657             :                                 if ([self checkKeyPress:n_key_rotate_cargo] || joyButtonState[BUTTON_ROTATECARGO])
    1658             :                                 {
    1659             :                                         if ((!rotateCargo_pressed)&&([cargo count] > 0))
    1660             :                                                 [self rotateCargo];
    1661             :                                         rotateCargo_pressed = YES;
    1662             :                                 }
    1663             :                                 else
    1664             :                                         rotateCargo_pressed = NO;
    1665             :                                 
    1666             :                                 exceptionContext = @"autopilot C";
    1667             :                                 // autopilot 'c'
    1668             :                                 if ([self checkKeyPress:n_key_autopilot] || joyButtonState[BUTTON_DOCKCPU])   // look for the 'c' key
    1669             :                                 {
    1670             :                                         if ([self hasDockingComputer] && (!autopilot_key_pressed))
    1671             :                                         {
    1672             :                                                 [self handleAutopilotOn:false];
    1673             :                                         }
    1674             :                                         autopilot_key_pressed = YES;
    1675             :                                 }
    1676             :                                 else
    1677             :                                         autopilot_key_pressed = NO;
    1678             :                                 
    1679             :                                 exceptionContext = @"autopilot shift-C";
    1680             :                                 // autopilot 'C' - fast-autopilot
    1681             :                                 if ([self checkKeyPress:n_key_autodock] || joyButtonState[BUTTON_DOCKCPUFAST])   // look for the 'C' key
    1682             :                                 {
    1683             :                                         if ([self hasDockingComputer] && (!fast_autopilot_key_pressed))
    1684             :                                         {
    1685             :                                                 [self handleAutopilotOn:true];
    1686             :                                         }
    1687             :                                         fast_autopilot_key_pressed = YES;
    1688             :                                 }
    1689             :                                 else
    1690             :                                 {
    1691             :                                         fast_autopilot_key_pressed = NO;
    1692             :                                 }
    1693             :                                 
    1694             :                                 exceptionContext = @"docking clearance request";
    1695             : 
    1696             :                                 if ([self checkKeyPress:n_key_docking_clearance_request] || joyButtonState[BUTTON_DOCKINGCLEARANCE])
    1697             :                                 {
    1698             :                                         if (!docking_clearance_request_key_pressed)
    1699             :                                         {
    1700             :                                                 Entity *primeTarget = [self primaryTarget];
    1701             :                                                 [self performDockingRequest:(StationEntity*)primeTarget];
    1702             :                                         }
    1703             :                                         docking_clearance_request_key_pressed = YES;
    1704             :                                 }
    1705             :                                 else
    1706             :                                 {
    1707             :                                         docking_clearance_request_key_pressed = NO;
    1708             :                                 }
    1709             :                                 
    1710             :                                 exceptionContext = @"hyperspace";
    1711             :                                 // hyperspace 'h'
    1712             :                                 if ( ([self checkKeyPress:n_key_hyperspace] || joyButtonState[BUTTON_HYPERDRIVE]) &&
    1713             :                                           [self hasHyperspaceMotor] )   // look for the 'h' key
    1714             :                                 {
    1715             :                                         if (!hyperspace_pressed)
    1716             :                                         {
    1717             :                                                 if ([self status] == STATUS_WITCHSPACE_COUNTDOWN)
    1718             :                                                 {
    1719             :                                                         [self cancelWitchspaceCountdown];
    1720             :                                                         if (galactic_witchjump)
    1721             :                                                         {
    1722             :                                                                 galactic_witchjump = NO;
    1723             :                                                                 [UNIVERSE addMessage:DESC(@"witch-user-galactic-abort") forCount:3.0];
    1724             :                                                         }
    1725             :                                                         else
    1726             :                                                         {
    1727             :                                                                 [UNIVERSE addMessage:DESC(@"witch-user-abort") forCount:3.0];
    1728             :                                                         }
    1729             :                                                 }
    1730             :                                                 else if ([self witchJumpChecklist:false])
    1731             :                                                 {
    1732             :                                                         [self beginWitchspaceCountdown:hyperspaceMotorSpinTime];
    1733             :                                                 }
    1734             :                                         }
    1735             :                                         hyperspace_pressed = YES;
    1736             :                                 }
    1737             :                                 else
    1738             :                                         hyperspace_pressed = NO;
    1739             :                                 
    1740             :                                 exceptionContext = @"galactic hyperspace";
    1741             :                                 // Galactic hyperspace 'g'
    1742             :                                 if (([self checkKeyPress:n_key_galactic_hyperspace] || joyButtonState[BUTTON_GALACTICDRIVE]) &&
    1743             :                                         ([self hasEquipmentItemProviding:@"EQ_GAL_DRIVE"]))// look for the 'g' key
    1744             :                                 {
    1745             :                                         if (!galhyperspace_pressed)
    1746             :                                         {
    1747             :                                                 if ([self status] == STATUS_WITCHSPACE_COUNTDOWN)
    1748             :                                                 {
    1749             :                                                         [self cancelWitchspaceCountdown];
    1750             :                                                         if (galactic_witchjump)
    1751             :                                                         {
    1752             :                                                                 galactic_witchjump = NO;
    1753             :                                                                 [UNIVERSE addMessage:DESC(@"witch-user-galactic-abort") forCount:3.0];
    1754             :                                                         }
    1755             :                                                         else
    1756             :                                                         {
    1757             :                                                                 [UNIVERSE addMessage:DESC(@"witch-user-abort") forCount:3.0];
    1758             :                                                         }
    1759             :                                                 }
    1760             :                                                 else
    1761             :                                                 {
    1762             :                                                         galactic_witchjump = YES;
    1763             :                                                         
    1764             :                                                         // even if we don't have a witchspace motor, we can still do a default galactic jump (!)
    1765             :                                                         if(EXPECT([self hasHyperspaceMotor])) witchspaceCountdown = hyperspaceMotorSpinTime;
    1766             :                                                         else witchspaceCountdown = DEFAULT_HYPERSPACE_SPIN_TIME;
    1767             :                                                         
    1768             :                                                         [self setStatus:STATUS_WITCHSPACE_COUNTDOWN];
    1769             :                                                         [self playGalacticHyperspace];
    1770             :                                                         // say it!
    1771             :                                                         [UNIVERSE addMessage:[NSString stringWithFormat:DESC(@"witch-galactic-in-f-seconds"), witchspaceCountdown] forCount:1.0];
    1772             :                                                         // FIXME: how to preload target system for hyperspace jump?
    1773             :                                                         
    1774             :                                                         [self doScriptEvent:OOJSID("playerStartedJumpCountdown")
    1775             :                                                                   withArguments:[NSArray arrayWithObjects:@"galactic", [NSNumber numberWithFloat:witchspaceCountdown], nil]];
    1776             :                                                 }
    1777             :                                         }
    1778             :                                         galhyperspace_pressed = YES;
    1779             :                                 }
    1780             :                                 else
    1781             :                                         galhyperspace_pressed = NO;
    1782             : 
    1783             :                         }
    1784             : 
    1785             : #if OO_FOV_INFLIGHT_CONTROL_ENABLED
    1786             :                         // Field of view controls
    1787             :                         if (![UNIVERSE displayGUI])
    1788             :                         {
    1789             :                                 if (([self checkKeyPress:n_key_inc_field_of_view] || joyButtonState[BUTTON_INC_FIELD_OF_VIEW]) && (fieldOfView < MAX_FOV))
    1790             :                                 {
    1791             :                                         fieldOfView *= pow(fov_delta, delta_t);
    1792             :                                         if (fieldOfView > MAX_FOV)  fieldOfView = MAX_FOV;
    1793             :                                 }
    1794             : 
    1795             :                                 if (([self checkKeyPress:n_key_dec_field_of_view] || joyButtonState[BUTTON_DEC_FIELD_OF_VIEW]) && (fieldOfView > MIN_FOV))
    1796             :                                 {
    1797             :                                         fieldOfView /= pow(fov_delta, delta_t);
    1798             :                                         if (fieldOfView < MIN_FOV)  fieldOfView = MIN_FOV;
    1799             :                                 }
    1800             : 
    1801             :                                 NSDictionary *functionForFovAxis = [[stickHandler axisFunctions] oo_dictionaryForKey:[[NSNumber numberWithInt:AXIS_FIELD_OF_VIEW] stringValue]];
    1802             :                                 if ([stickHandler joystickCount] != 0 && functionForFovAxis != nil)
    1803             :                                 {
    1804             :                                         // TODO think reqFov through
    1805             :                                         double reqFov = [stickHandler getAxisState: AXIS_FIELD_OF_VIEW];
    1806             :                                         if (fieldOfView < maxFieldOfView * reqFov)
    1807             :                                         {
    1808             :                                                 fieldOfView *= pow(fov_delta, delta_t);
    1809             :                                                 if (fieldOfView > MAX_FOV)  fieldOfView = MAX_FOV;
    1810             :                                         }
    1811             :                                         if (fieldOfView > maxFieldOfView * reqFov)
    1812             :                                         {
    1813             :                                                 fieldOfView /= pow(fov_delta, delta_t);
    1814             :                                                 if (fieldOfView < MIN_FOV)  fieldOfView = MIN_FOV;
    1815             :                                         }
    1816             :                                 }
    1817             :                         }
    1818             : #endif
    1819             : 
    1820             :         #ifndef NDEBUG
    1821             :                         exceptionContext = @"dump target state";
    1822             :                         if ([self checkKeyPress:n_key_dump_target_state])
    1823             :                         {
    1824             :                                 if (!dump_target_state_pressed)
    1825             :                                 {
    1826             :                                         dump_target_state_pressed = YES;
    1827             :                                         id target = [self primaryTarget];
    1828             :                                         if (target == nil)      target = self;
    1829             :                                         [target dumpState];
    1830             :                                 }
    1831             :                         }
    1832             :                         else  dump_target_state_pressed = NO;
    1833             :         #endif
    1834             :                         
    1835             :                         //  text displays
    1836             :                         exceptionContext = @"pollGuiScreenControls";
    1837             :                         [self pollGuiScreenControls];
    1838             :                 }
    1839             :                 else
    1840             :                 {
    1841             :                         // game is paused
    1842             :                         // check options menu request
    1843             :                         exceptionContext = @"options menu";
    1844             :                         if (([self checkKeyPress:n_key_gui_screen_options]) && (gui_screen != GUI_SCREEN_OPTIONS) && ![gameView allowingStringInput])
    1845             :                         {
    1846             :                                 [gameView clearKeys];
    1847             :                                 [self setGuiToLoadSaveScreen];
    1848             :                         }
    1849             :                         
    1850             :                         #if (ALLOW_CUSTOM_VIEWS_WHILE_PAUSED)
    1851             :                         [self pollCustomViewControls];  // allow custom views during pause
    1852             :                         #endif
    1853             :                         
    1854             :                         if (gui_screen == GUI_SCREEN_OPTIONS || gui_screen == GUI_SCREEN_GAMEOPTIONS || gui_screen == GUI_SCREEN_STICKMAPPER || 
    1855             :                                 gui_screen == GUI_SCREEN_STICKPROFILE || gui_screen == GUI_SCREEN_KEYBOARD || gui_screen == GUI_SCREEN_KEYBOARD_CONFIRMCLEAR ||
    1856             :                                 gui_screen == GUI_SCREEN_KEYBOARD_CONFIG || gui_screen == GUI_SCREEN_KEYBOARD_ENTRY || gui_screen == GUI_SCREEN_KEYBOARD_LAYOUT)
    1857             :                         {
    1858             :                                 if ([UNIVERSE pauseMessageVisible]) [[UNIVERSE messageGUI] leaveLastLine];
    1859             :                                 else [[UNIVERSE messageGUI] clear];
    1860             :                                 NSTimeInterval  time_this_frame = [NSDate timeIntervalSinceReferenceDate];
    1861             :                                 OOTimeDelta             time_delta;
    1862             :                                 if (![[GameController sharedController] isGamePaused])
    1863             :                                 {
    1864             :                                         time_delta = time_this_frame - time_last_frame;
    1865             :                                         time_last_frame = time_this_frame;
    1866             :                                         time_delta = OOClamp_0_max_d(time_delta, MINIMUM_GAME_TICK);
    1867             :                                 }
    1868             :                                 else
    1869             :                                 {
    1870             :                                         time_delta = 0.0;
    1871             :                                 }
    1872             :                                 
    1873             :                                 script_time += time_delta;
    1874             :                                 [self pollGuiArrowKeyControls:time_delta];
    1875             :                         }
    1876             :                         
    1877             :                         exceptionContext = @"debug keys";
    1878             :         #ifndef NDEBUG
    1879             :                         // look for debugging keys
    1880             :                         if ([self checkKeyPress:n_key_dump_entity_list] && ![gameView allowingStringInput])// look for the '0' key
    1881             :                         {
    1882             :                                 if (!dump_entity_list_pressed)
    1883             :                                 {
    1884             :                                         [UNIVERSE debugDumpEntities];
    1885             :                                         gDebugFlags = 0;
    1886             :                                         [UNIVERSE addMessage:@"Entity List dumped. Debugging OFF" forCount:3];
    1887             :                                 }
    1888             :                                 dump_entity_list_pressed = YES;
    1889             :                         }
    1890             :                         else
    1891             :                                 dump_entity_list_pressed = NO;
    1892             :                         
    1893             :                         // look for debugging keys
    1894             :                         if ([self checkKeyPress:n_key_debug_full] && ![gameView allowingStringInput])// look for the 'd' key
    1895             :                         {
    1896             :                                 gDebugFlags = DEBUG_ALL;
    1897             :                                 [UNIVERSE addMessage:@"Full debug ON" forCount:3];
    1898             :                         }
    1899             :                         
    1900             :                         if ([self checkKeyPress:n_key_debug_collision] && ![gameView allowingStringInput])// look for the 'b' key
    1901             :                         {
    1902             :                                 gDebugFlags |= DEBUG_COLLISIONS;
    1903             :                                 [UNIVERSE addMessage:@"Collision debug ON" forCount:3];
    1904             :                         }
    1905             :                         
    1906             :                         if ([self checkKeyPress:n_key_debug_console_connect] && ![[OODebugMonitor sharedDebugMonitor] usingPlugInController] && ![gameView allowingStringInput]) // look for the 'c' key
    1907             :                         {
    1908             :                                 // This code is executed only if we're not using the integrated plugin controller
    1909             :                                 if (!autopilot_key_pressed)
    1910             :                                 {
    1911             :                                         if (![[OODebugMonitor sharedDebugMonitor] debuggerConnected])
    1912             :                                         {
    1913             :                                                 OOInitDebugSupport();
    1914             :                                                 if ([[OODebugMonitor sharedDebugMonitor] debuggerConnected])
    1915             :                                                         [UNIVERSE addMessage:@"Connected to debug console." forCount:3];
    1916             :                                         }
    1917             :                                         else
    1918             :                                         {
    1919             :                                                 [[OODebugMonitor sharedDebugMonitor] setDebugger:nil];
    1920             :                                                 [UNIVERSE addMessage:@"Disconnected from debug console." forCount:3];
    1921             :                                         }
    1922             :                                 }
    1923             :                                 autopilot_key_pressed = YES;
    1924             :                         }
    1925             :                         else
    1926             :                                 autopilot_key_pressed = NO;
    1927             :                         
    1928             :                         if ([self checkKeyPress:n_key_debug_bounding_boxes] && ![gameView allowingStringInput])// look for the 'x' key
    1929             :                         {
    1930             :                                 gDebugFlags |= DEBUG_BOUNDING_BOXES;
    1931             :                                 [UNIVERSE addMessage:@"Bounding box debug ON" forCount:3];
    1932             :                         }
    1933             :                         
    1934             :                         if ([self checkKeyPress:n_key_debug_shaders] && ![gameView allowingStringInput])// look for the 's' key
    1935             :                         {
    1936             :                                 OOLogSetDisplayMessagesInClass(@"$shaderDebugOn", YES);
    1937             :                                 [UNIVERSE addMessage:@"Shader debug ON" forCount:3];
    1938             :                         }
    1939             : 
    1940             :                         if (([self checkKeyPress:n_key_gui_arrow_left] || [self checkKeyPress:n_key_gui_arrow_right]) && gui_screen != GUI_SCREEN_GAMEOPTIONS && [UNIVERSE displayFPS] && ![gameView allowingStringInput])
    1941             :                         {
    1942             :                                 if (!leftRightKeyPressed)
    1943             :                                 {
    1944             :                                         float newTimeAccelerationFactor = [self checkKeyPress:n_key_gui_arrow_left] ?
    1945             :                                                         fmax([UNIVERSE timeAccelerationFactor] / 2.0f, TIME_ACCELERATION_FACTOR_MIN) :
    1946             :                                                         fmin([UNIVERSE timeAccelerationFactor] * 2.0f, TIME_ACCELERATION_FACTOR_MAX);
    1947             :                                         [UNIVERSE setTimeAccelerationFactor:newTimeAccelerationFactor];
    1948             :                                 }
    1949             :                                 leftRightKeyPressed = YES;
    1950             :                         }
    1951             :                         else
    1952             :                                 leftRightKeyPressed = NO;
    1953             :                                         
    1954             :                         
    1955             :                         if ([self checkKeyPress:n_key_debug_off] && ![gameView allowingStringInput])// look for the 'n' key
    1956             :                         {
    1957             :                                 gDebugFlags = 0;
    1958             :                                 [UNIVERSE addMessage:@"All debug flags OFF" forCount:3];
    1959             :                                 OOLogSetDisplayMessagesInClass(@"$shaderDebugOn", NO);
    1960             :                         }
    1961             :         #endif
    1962             :                 }
    1963             :                 
    1964             :                 exceptionContext = @"pause";
    1965             :                 // Pause game 'p'
    1966             :                 if (([self checkKeyPress:n_key_pausebutton] || joyButtonState[BUTTON_PAUSE]) && gui_screen != GUI_SCREEN_LONG_RANGE_CHART && gui_screen != GUI_SCREEN_MISSION && ![gameView allowingStringInput])// look for the 'p' key
    1967             :                 {
    1968             :                         if (!pause_pressed)
    1969             :                         {
    1970             :                                 if (paused)
    1971             :                                 {
    1972             :                                         script_time = saved_script_time;
    1973             :                                         // Reset to correct GUI screen, if we are unpausing from one.
    1974             :                                         // Don't set gui_screen here, use setGuis - they also switch backgrounds.
    1975             :                                         // No gui switching events will be triggered while still paused.
    1976             :                                         switch (saved_gui_screen)
    1977             :                                         {
    1978             :                                                 case GUI_SCREEN_STATUS:
    1979             :                                                         [self setGuiToStatusScreen];
    1980             :                                                         break;
    1981             :                                                 case GUI_SCREEN_LONG_RANGE_CHART:
    1982             :                                                         [self setGuiToLongRangeChartScreen];
    1983             :                                                         break;
    1984             :                                                 case GUI_SCREEN_SHORT_RANGE_CHART:
    1985             :                                                         [self setGuiToShortRangeChartScreen];
    1986             :                                                         break;
    1987             :                                                 case GUI_SCREEN_MANIFEST:
    1988             :                                                         [self setGuiToManifestScreen];
    1989             :                                                         break;
    1990             :                                                 case GUI_SCREEN_MARKET:
    1991             :                                                         [self setGuiToMarketScreen];
    1992             :                                                         break;
    1993             :                                                 case GUI_SCREEN_MARKETINFO:
    1994             :                                                         [self setGuiToMarketInfoScreen];
    1995             :                                                         break;
    1996             :                                                 case GUI_SCREEN_SYSTEM_DATA:
    1997             :                                                         // Do not reset planet rotation if we are already in the system info screen!
    1998             :                                                         if (gui_screen != GUI_SCREEN_SYSTEM_DATA)
    1999             :                                                                 [self setGuiToSystemDataScreen];
    2000             :                                                         break;
    2001             :                                                 default:
    2002             :                                                         gui_screen = saved_gui_screen;  // make sure we're back to the right screen
    2003             :                                                         break;
    2004             :                                         }
    2005             :                                         [gameView allowStringInput:NO];
    2006             :                                         [UNIVERSE clearPreviousMessage];
    2007             :                                         [UNIVERSE setViewDirection:saved_view_direction];
    2008             :                                         currentWeaponFacing = saved_weapon_facing;
    2009             :                                         // make sure the light comes from the right direction after resuming from pause!
    2010             :                                         if (saved_gui_screen == GUI_SCREEN_SYSTEM_DATA) [UNIVERSE setMainLightPosition:_sysInfoLight];
    2011             :                                         [[UNIVERSE gui] setForegroundTextureKey:@"overlay"];
    2012             :                                         [[UNIVERSE gameController] setGamePaused:NO];
    2013             :                                 }
    2014             :                                 else
    2015             :                                 {
    2016             :                                         saved_view_direction = [UNIVERSE viewDirection];
    2017             :                                         saved_script_time = script_time;
    2018             :                                         saved_gui_screen = gui_screen;
    2019             :                                         saved_weapon_facing = currentWeaponFacing;
    2020             :                                         [UNIVERSE pauseGame];   // pause handler
    2021             :                                 }
    2022             :                         }
    2023             :                         pause_pressed = YES;
    2024             :                 }
    2025             :                 else
    2026             :                 {
    2027             :                         pause_pressed = NO;
    2028             :                 }
    2029             :         }
    2030             :         @catch (NSException *exception)
    2031             :         {
    2032             :                 OOLog(kOOLogException, @"***** Exception in pollFlightControls [%@]: %@ : %@", exceptionContext, [exception name], [exception reason]);
    2033             :         }
    2034             : }
    2035             : 
    2036             : 
    2037             : - (void) pollGuiArrowKeyControls:(double) delta_t
    2038             : {
    2039             :         MyOpenGLView    *gameView = [UNIVERSE gameView];
    2040             :         BOOL                    moving = NO;
    2041             :         BOOL                    dragging = NO;
    2042             :         double                  cursor_speed = ([gameView isCtrlDown] ? 20.0 : 10.0)* chart_zoom;
    2043             :         GameController  *controller = [UNIVERSE gameController];
    2044             :         GuiDisplayGen   *gui = [UNIVERSE gui];
    2045             :         GUI_ROW_INIT(gui);
    2046             :         
    2047             :         // deal with string inputs as necessary
    2048             :         if (gui_screen == GUI_SCREEN_LONG_RANGE_CHART)
    2049             :         {
    2050             :                 [gameView setStringInput: gvStringInputAlpha];
    2051             :         }
    2052             :         else if (gui_screen == GUI_SCREEN_SAVE)
    2053             :         {
    2054             :                 [gameView setStringInput: gvStringInputLoadSave];
    2055             :         }
    2056             :         else if (gui_screen == GUI_SCREEN_MISSION && _missionTextEntry)
    2057             :         {
    2058             :                 [gameView setStringInput: gvStringInputAll];
    2059             :         }
    2060             :         else if (gui_screen == GUI_SCREEN_KEYBOARD_ENTRY)
    2061             :         {
    2062             :                 [gameView setStringInput: gvStringInputAll];
    2063             :         }
    2064             : #if 0
    2065             :         // at the moment this function is never called for GUI_SCREEN_OXZMANAGER
    2066             :         // but putting this here in case we do later
    2067             :         else if (gui_screen == GUI_SCREEN_OXZMANAGER && [[OOOXZManager sharedManager] isAcceptingTextInput])
    2068             :         {
    2069             :                 [gameView setStringInput: gvStringInputAll];
    2070             :         }
    2071             : #endif
    2072             :         else
    2073             :         {
    2074             :                 [gameView allowStringInput: NO];
    2075             :                 // If we have entered this screen with the injectors key pressed, make sure
    2076             :                 // that injectors switch off when we release it - Nikos.
    2077             :                 if (afterburner_engaged && ![self checkKeyPress:n_key_inject_fuel])
    2078             :                 {
    2079             :                         afterburner_engaged = NO;
    2080             :                 }
    2081             :                         
    2082             :         }
    2083             :         
    2084             :         switch (gui_screen)
    2085             :         {
    2086             :                 case GUI_SCREEN_LONG_RANGE_CHART:
    2087             : 
    2088             :                         if ([self status] != STATUS_WITCHSPACE_COUNTDOWN)
    2089             :                         {
    2090             :                                 if ([[gameView typedString] length] > 0)
    2091             :                                 {
    2092             :                                         planetSearchString = [[[gameView typedString] lowercaseString] retain];
    2093             :                                         NSPoint search_coords = [UNIVERSE findSystemCoordinatesWithPrefix:planetSearchString];
    2094             :                                         if ((search_coords.x >= 0.0)&&(search_coords.y >= 0.0))
    2095             :                                         {
    2096             :                                                 // always reset the found system index at the beginning of a new search
    2097             :                                                 if ([planetSearchString length] == 1) [[UNIVERSE gui] targetNextFoundSystem:0];
    2098             :                                                 
    2099             :                                                 // Always select the right one out of 2 overlapping systems.
    2100             :                                                 [self targetNewSystem:0 whileTyping:YES];
    2101             :                                         }
    2102             :                                         else
    2103             :                                         {
    2104             :                                                 found_system_id = -1;
    2105             :                                                 [self clearPlanetSearchString];
    2106             :                                         }
    2107             :                                 }
    2108             :                                 else
    2109             :                                 {
    2110             :                                         if ([gameView isDown:gvDeleteKey]) // did we just delete the string ?
    2111             :                                         {
    2112             :                                                 found_system_id = -1;
    2113             :                                                 [UNIVERSE findSystemCoordinatesWithPrefix:@""];
    2114             :                                         }
    2115             :                                         if (planetSearchString) [planetSearchString release];
    2116             :                                         planetSearchString = nil;
    2117             :                                 }
    2118             :                                 
    2119             :                                 moving |= (searchStringLength != [[gameView typedString] length]);
    2120             :                                 searchStringLength = [[gameView typedString] length];
    2121             :                         }
    2122             : 
    2123             :                 case GUI_SCREEN_SHORT_RANGE_CHART:
    2124             : 
    2125             :                         if ([self checkKeyPress:n_key_chart_highlight])
    2126             :                         {
    2127             :                                 if (!queryPressed)
    2128             :                                 {
    2129             :                                         OOLongRangeChartMode mode = [self longRangeChartMode];
    2130             :                                         if (mode != OOLRC_MODE_TECHLEVEL)
    2131             :                                         {
    2132             :                                                 [self setLongRangeChartMode:mode+1];
    2133             :                                         }
    2134             :                                         else
    2135             :                                         {
    2136             :                                                 [self setLongRangeChartMode:OOLRC_MODE_SUNCOLOR];
    2137             :                                         }
    2138             :                                         [self doScriptEvent:OOJSID("chartHighlightModeChanged") withArgument:OOStringFromLongRangeChartMode([self longRangeChartMode])];
    2139             :                                 }
    2140             :                                 queryPressed = YES;
    2141             :                         }
    2142             :                         else
    2143             :                         {
    2144             :                                 queryPressed = NO;
    2145             :                         }
    2146             :                         
    2147             :                         if ([self checkKeyPress:n_key_map_info] && chart_zoom <= CHART_ZOOM_SHOW_LABELS)
    2148             :                         {
    2149             :                                 if (!chartInfoPressed)
    2150             :                                 {
    2151             :                                         show_info_flag = !show_info_flag;
    2152             :                                         chartInfoPressed = YES;
    2153             :                                 }
    2154             :                         }
    2155             :                         else
    2156             :                         {
    2157             :                                 chartInfoPressed = NO;
    2158             :                         }
    2159             :                         
    2160             :                         if ([self status] != STATUS_WITCHSPACE_COUNTDOWN)
    2161             :                         {
    2162             :                                 if ([self hasEquipmentItemProviding:@"EQ_ADVANCED_NAVIGATIONAL_ARRAY"])
    2163             :                                 {
    2164             :                                         if ([self checkKeyPress:n_key_advanced_nav_array_next] || [self checkKeyPress:n_key_advanced_nav_array_previous])
    2165             :                                         {
    2166             :                                                 if (!pling_pressed)
    2167             :                                                 {
    2168             :                                                         if ([self checkKeyPress:n_key_advanced_nav_array_previous])
    2169             :                                                         {
    2170             :                                                                 switch (ANA_mode)
    2171             :                                                                 {
    2172             :                                                                 case OPTIMIZED_BY_NONE: ANA_mode = OPTIMIZED_BY_TIME;   break;
    2173             :                                                                 case OPTIMIZED_BY_TIME: ANA_mode = OPTIMIZED_BY_JUMPS;  break;
    2174             :                                                                 default:                ANA_mode = OPTIMIZED_BY_NONE;   break;
    2175             :                                                                 }
    2176             :                                                         }
    2177             :                                                         else
    2178             :                                                         {
    2179             :                                                                 switch (ANA_mode)
    2180             :                                                                 {
    2181             :                                                                 case OPTIMIZED_BY_NONE: ANA_mode = OPTIMIZED_BY_JUMPS;  break;
    2182             :                                                                 case OPTIMIZED_BY_JUMPS:ANA_mode = OPTIMIZED_BY_TIME;   break;
    2183             :                                                                 default:                ANA_mode = OPTIMIZED_BY_NONE;   break;
    2184             :                                                                 }
    2185             :                                                         }
    2186             :                                                         if (ANA_mode == OPTIMIZED_BY_NONE || ![self infoSystemOnRoute])
    2187             :                                                         {
    2188             :                                                                 [self setInfoSystemID: target_system_id moveChart: NO];
    2189             :                                                         }
    2190             :                                                 }
    2191             :                                                 pling_pressed = YES;
    2192             :                                         }
    2193             :                                         else
    2194             :                                         {
    2195             :                                                 pling_pressed = NO;
    2196             :                                         }
    2197             :                                 }
    2198             :                                 else
    2199             :                                 {
    2200             :                                         ANA_mode = OPTIMIZED_BY_NONE;
    2201             :                                 }
    2202             : 
    2203             :                                 if ([gameView isDown:gvMouseDoubleClick])
    2204             :                                 {
    2205             :                                         [gameView clearMouse];
    2206             :                                         mouse_left_down = NO;
    2207             :                                         [self noteGUIWillChangeTo:GUI_SCREEN_SYSTEM_DATA];
    2208             :                                         showingLongRangeChart = (gui_screen == GUI_SCREEN_LONG_RANGE_CHART);
    2209             :                                         [self setGuiToSystemDataScreen];
    2210             :                                         break;
    2211             :                                 }
    2212             :                                 if ([gameView isDown:gvMouseLeftButton])
    2213             :                                 {
    2214             :                                         NSPoint maus = [gameView virtualJoystickPosition];
    2215             :                                         double vadjust = MAIN_GUI_PIXEL_HEIGHT/2.0 - CHART_SCREEN_VERTICAL_CENTRE;
    2216             :                                         double hscale = MAIN_GUI_PIXEL_WIDTH / (64.0 * chart_zoom);
    2217             :                                         double vscale = MAIN_GUI_PIXEL_HEIGHT / (128.0 * chart_zoom);
    2218             :                                         if (mouse_left_down == NO)
    2219             :                                         {
    2220             :                                                 NSPoint centre = [self adjusted_chart_centre];
    2221             :                                                 centre_at_mouse_click = chart_centre_coordinates;
    2222             :                                                 mouse_click_position = maus;
    2223             :                                                 chart_focus_coordinates.x = OOClamp_0_max_f(centre.x + (maus.x * MAIN_GUI_PIXEL_WIDTH) / hscale, 256.0);
    2224             :                                                 chart_focus_coordinates.y = OOClamp_0_max_f(centre.y + (maus.y * MAIN_GUI_PIXEL_HEIGHT + vadjust) / vscale, 256.0);
    2225             :                                                 target_chart_focus = chart_focus_coordinates;
    2226             :                                         }
    2227             :                                         if (fabs(maus.x - mouse_click_position.x)*MAIN_GUI_PIXEL_WIDTH > 2 ||
    2228             :                                                 fabs(maus.y - mouse_click_position.y)*MAIN_GUI_PIXEL_HEIGHT > 2)
    2229             :                                         {
    2230             :                                                 chart_centre_coordinates.x = OOClamp_0_max_f(centre_at_mouse_click.x - (maus.x - mouse_click_position.x)*MAIN_GUI_PIXEL_WIDTH/hscale, 256.0);
    2231             :                                                 chart_centre_coordinates.y = OOClamp_0_max_f(centre_at_mouse_click.y - (maus.y - mouse_click_position.y)*MAIN_GUI_PIXEL_HEIGHT/vscale, 256.0);
    2232             :                                                 target_chart_centre = chart_centre_coordinates;
    2233             :                                                 dragging = YES;
    2234             :                                         }
    2235             :                                         if (gui_screen == GUI_SCREEN_LONG_RANGE_CHART)
    2236             :                                                 [gameView resetTypedString];
    2237             :                                         mouse_left_down = YES;
    2238             :                                 }
    2239             :                                 else if (mouse_left_down == YES) 
    2240             :                                 {
    2241             :                                         NSPoint maus = [gameView virtualJoystickPosition];
    2242             :                                         if (fabs(maus.x - mouse_click_position.x)*MAIN_GUI_PIXEL_WIDTH <= 2 &&
    2243             :                                                 fabs(maus.y - mouse_click_position.y)*MAIN_GUI_PIXEL_HEIGHT <= 2)
    2244             :                                         {
    2245             :                                                 cursor_coordinates = chart_focus_coordinates;
    2246             :                                                 moving = YES;
    2247             :                                         }
    2248             :                                         else
    2249             :                                         {
    2250             :                                                 dragging = YES;
    2251             :                                         }
    2252             :                                         mouse_left_down = NO;
    2253             :                                 }
    2254             :                                 if ([self checkKeyPress:n_key_map_home])
    2255             :                                 {
    2256             :                                         if ([gameView isOptDown])
    2257             :                                         {
    2258             :                                                 [self homeInfoSystem];
    2259             :                                                 target_chart_focus = galaxy_coordinates;
    2260             :                                         }
    2261             :                                         else
    2262             :                                         {
    2263             :                                                 [gameView resetTypedString];
    2264             :                                                 cursor_coordinates = galaxy_coordinates;
    2265             :                                                 target_chart_focus = cursor_coordinates;
    2266             :                                                 target_chart_centre = galaxy_coordinates;
    2267             :                                                 found_system_id = -1;
    2268             :                                                 [UNIVERSE findSystemCoordinatesWithPrefix:@""];
    2269             :                                                 moving = YES;
    2270             :                                         }
    2271             :                                 }
    2272             :                                 if ([self checkKeyPress:n_key_map_end])
    2273             :                                 {
    2274             :                                         [self targetInfoSystem];
    2275             :                                         target_chart_focus = cursor_coordinates;
    2276             :                                 }
    2277             :                                 if ([self checkKeyPress:n_key_map_zoom_in] || [gameView mouseWheelState] == gvMouseWheelDown)
    2278             :                                 {
    2279             :                                         target_chart_zoom *= CHART_ZOOM_SPEED_FACTOR;
    2280             :                                         if (target_chart_zoom > CHART_MAX_ZOOM) target_chart_zoom = CHART_MAX_ZOOM;
    2281             :                                         saved_chart_zoom = target_chart_zoom;
    2282             :                                 }
    2283             :                                 if ([self checkKeyPress:n_key_map_zoom_out] || [gameView mouseWheelState] == gvMouseWheelUp)
    2284             :                                 {
    2285             :                                         if (gui_screen == GUI_SCREEN_LONG_RANGE_CHART)
    2286             :                                         {
    2287             :                                                 target_chart_zoom = CHART_MAX_ZOOM;
    2288             :                                                 [self setGuiToShortRangeChartScreen];
    2289             :                                         }
    2290             :                                         target_chart_zoom /= CHART_ZOOM_SPEED_FACTOR;
    2291             :                                         if (target_chart_zoom < 1.0) target_chart_zoom = 1.0;
    2292             :                                         saved_chart_zoom = target_chart_zoom;
    2293             :                                         //target_chart_centre = cursor_coordinates;
    2294             :                                         target_chart_focus = target_chart_centre;
    2295             :                                 }
    2296             :                                 
    2297             :                                 BOOL nextSystem = [gameView isShiftDown];
    2298             :                                 BOOL nextSystemOnRoute = [gameView isOptDown];
    2299             :                                 
    2300             :                                 if ([self checkNavKeyPress:n_key_gui_arrow_left])
    2301             :                                 {
    2302             :                                         if ((nextSystem || nextSystemOnRoute) && pressedArrow != 1)
    2303             :                                         {
    2304             :                                                 if (nextSystem)
    2305             :                                                 {
    2306             :                                                         [self targetNewSystem:-1];
    2307             :                                                         target_chart_focus = cursor_coordinates;
    2308             :                                                 }
    2309             :                                                 else
    2310             :                                                 {
    2311             :                                                         [self clearPlanetSearchString];
    2312             :                                                         [self previousInfoSystem];
    2313             :                                                         target_chart_focus = [[UNIVERSE systemManager] getCoordinatesForSystem:info_system_id inGalaxy:galaxy_number];
    2314             :                                                 }
    2315             :                                                 pressedArrow = 1;
    2316             :                                         }
    2317             :                                         else if (!nextSystem && !nextSystemOnRoute)
    2318             :                                         {
    2319             :                                                 [gameView resetTypedString];
    2320             :                                                 cursor_coordinates.x -= cursor_speed*delta_t;
    2321             :                                                 if (cursor_coordinates.x < 0.0) cursor_coordinates.x = 0.0;
    2322             :                                                 moving = YES;
    2323             :                                                 target_chart_focus = cursor_coordinates;
    2324             :                                         }
    2325             :                                 }
    2326             :                                 else
    2327             :                                         pressedArrow =  pressedArrow == 1 ? 0 : pressedArrow;
    2328             :                                 
    2329             :                                 if ([self checkNavKeyPress:n_key_gui_arrow_right])
    2330             :                                 {
    2331             :                                         if ((nextSystem || nextSystemOnRoute) && pressedArrow != 2)
    2332             :                                         {
    2333             :                                                 if (nextSystem)
    2334             :                                                 {
    2335             :                                                         [self targetNewSystem:+1];
    2336             :                                                         target_chart_focus = cursor_coordinates;
    2337             :                                                 }
    2338             :                                                 else
    2339             :                                                 {
    2340             :                                                         [self clearPlanetSearchString];
    2341             :                                                         [self nextInfoSystem];
    2342             :                                                         target_chart_focus = [[UNIVERSE systemManager] getCoordinatesForSystem:info_system_id inGalaxy:galaxy_number];
    2343             :                                                 }
    2344             :                                                 pressedArrow = 2;
    2345             :                                         }
    2346             :                                         else if (!nextSystem && !nextSystemOnRoute)
    2347             :                                         {
    2348             :                                                 [gameView resetTypedString];
    2349             :                                                 cursor_coordinates.x += cursor_speed*delta_t;
    2350             :                                                 if (cursor_coordinates.x > 256.0) cursor_coordinates.x = 256.0;
    2351             :                                                 moving = YES;
    2352             :                                                 target_chart_focus = cursor_coordinates;
    2353             :                                         }
    2354             :                                 }
    2355             :                                 else
    2356             :                                         pressedArrow =  pressedArrow == 2 ? 0 : pressedArrow;
    2357             :                                 
    2358             :                                 if ([self checkNavKeyPress:n_key_gui_arrow_down])
    2359             :                                 {
    2360             :                                         if (nextSystem && pressedArrow != 3)
    2361             :                                         {
    2362             :                                                 [self targetNewSystem:+1];
    2363             :                                                 pressedArrow = 3;
    2364             :                                         }
    2365             :                                         else if (!nextSystem)
    2366             :                                         {
    2367             :                                                 [gameView resetTypedString];
    2368             :                                                 cursor_coordinates.y += cursor_speed*delta_t*2.0;
    2369             :                                                 if (cursor_coordinates.y > 256.0) cursor_coordinates.y = 256.0;
    2370             :                                                 moving = YES;
    2371             :                                         }
    2372             :                                         target_chart_focus = cursor_coordinates;
    2373             :                                 }
    2374             :                                 else
    2375             :                                         pressedArrow =  pressedArrow == 3 ? 0 : pressedArrow;
    2376             :                                 
    2377             :                                 if ([self checkNavKeyPress:n_key_gui_arrow_up])
    2378             :                                 {
    2379             :                                         if (nextSystem && pressedArrow != 4)
    2380             :                                         {
    2381             :                                                 [self targetNewSystem:-1];
    2382             :                                                 pressedArrow = 4;
    2383             :                                         }       
    2384             :                                         else if (!nextSystem)
    2385             :                                         {
    2386             :                                                 [gameView resetTypedString];
    2387             :                                                 cursor_coordinates.y -= cursor_speed*delta_t*2.0;
    2388             :                                                 if (cursor_coordinates.y < 0.0) cursor_coordinates.y = 0.0;
    2389             :                                                 moving = YES;
    2390             :                                         }
    2391             :                                         target_chart_focus = cursor_coordinates;
    2392             :                                 }
    2393             :                                 else
    2394             :                                         pressedArrow =  pressedArrow == 4 ? 0 : pressedArrow;
    2395             :                                 if ((cursor_moving)&&(!moving))
    2396             :                                 {
    2397             :                                         if (found_system_id == -1)
    2398             :                                         {
    2399             :                                                 target_system_id = [UNIVERSE findSystemNumberAtCoords:cursor_coordinates withGalaxy:galaxy_number includingHidden:NO];
    2400             :                                                 [self setInfoSystemID: target_system_id moveChart: YES];
    2401             :                                         }
    2402             :                                         else
    2403             :                                         {
    2404             :                                                 // if found with a search string, don't recalculate! Required for overlapping systems, like Divees & Tezabi in galaxy 5
    2405             :                                                 NSPoint fpos = [[UNIVERSE systemManager] getCoordinatesForSystem:found_system_id inGalaxy:galaxy_number];
    2406             :                                                 if (fpos.x != cursor_coordinates.x && fpos.y != cursor_coordinates.y)
    2407             :                                                 {
    2408             :                                                         target_system_id = [UNIVERSE findSystemNumberAtCoords:cursor_coordinates withGalaxy:galaxy_number includingHidden:NO];
    2409             :                                                         [self setInfoSystemID: target_system_id moveChart: YES];
    2410             :                                                 }
    2411             :                                         }
    2412             :                                         cursor_coordinates = [[UNIVERSE systemManager] getCoordinatesForSystem:target_system_id inGalaxy:galaxy_number];
    2413             :                                 }
    2414             :                                 if (chart_focus_coordinates.x - target_chart_centre.x <= -CHART_SCROLL_AT_X*chart_zoom)
    2415             :                                 {
    2416             :                                         target_chart_centre.x = chart_focus_coordinates.x + CHART_SCROLL_AT_X*chart_zoom;
    2417             :                                 }
    2418             :                                 else if (chart_focus_coordinates.x - target_chart_centre.x >= CHART_SCROLL_AT_X*chart_zoom)
    2419             :                                 {
    2420             :                                         target_chart_centre.x = chart_focus_coordinates.x - CHART_SCROLL_AT_X*chart_zoom;
    2421             :                                 }
    2422             :                                 if (chart_focus_coordinates.y - target_chart_centre.y <= -CHART_SCROLL_AT_Y*chart_zoom)
    2423             :                                 {
    2424             :                                         target_chart_centre.y = chart_focus_coordinates.y + CHART_SCROLL_AT_Y*chart_zoom;
    2425             :                                 }
    2426             :                                 else if (chart_focus_coordinates.y - target_chart_centre.y >= CHART_SCROLL_AT_Y*chart_zoom)
    2427             :                                 {
    2428             :                                         target_chart_centre.y = chart_focus_coordinates.y - CHART_SCROLL_AT_Y*chart_zoom;
    2429             :                                 }
    2430             :                                 chart_centre_coordinates.x = (3.0*chart_centre_coordinates.x + target_chart_centre.x)/4.0;
    2431             :                                 chart_centre_coordinates.y = (3.0*chart_centre_coordinates.y + target_chart_centre.y)/4.0;
    2432             :                                 chart_zoom = (3.0*chart_zoom + target_chart_zoom)/4.0;
    2433             :                                 chart_focus_coordinates.x = (3.0*chart_focus_coordinates.x + target_chart_focus.x)/4.0;
    2434             :                                 chart_focus_coordinates.y = (3.0*chart_focus_coordinates.y + target_chart_focus.y)/4.0;
    2435             :                                 if (cursor_moving || dragging) [self setGuiToChartScreenFrom: gui_screen]; // update graphics
    2436             :                                 cursor_moving = moving;
    2437             :                         }
    2438             :                         break;
    2439             :                         
    2440             :                 case GUI_SCREEN_SYSTEM_DATA:
    2441             :                         if ([self checkKeyPress:n_key_system_next_system])
    2442             :                         {
    2443             :                                 if (!next_planet_info_pressed)
    2444             :                                 {
    2445             :                                         [self nextInfoSystem];
    2446             :                                         next_planet_info_pressed = YES;
    2447             :                                 }
    2448             :                         }
    2449             :                         else
    2450             :                         {
    2451             :                                 next_planet_info_pressed = NO;
    2452             :                         }
    2453             :                         if ([self checkKeyPress:n_key_system_previous_system])
    2454             :                         {
    2455             :                                 if (!previous_planet_info_pressed)
    2456             :                                 {
    2457             :                                         [self previousInfoSystem];
    2458             :                                         previous_planet_info_pressed = YES;
    2459             :                                 }
    2460             :                         }
    2461             :                         else
    2462             :                         {
    2463             :                                 previous_planet_info_pressed = NO;
    2464             :                         }
    2465             :                         if ([self checkKeyPress:n_key_system_home])
    2466             :                         {
    2467             :                                 if (!home_info_pressed)
    2468             :                                 {
    2469             :                                         [self homeInfoSystem];
    2470             :                                         home_info_pressed = YES;
    2471             :                                 }
    2472             :                         }
    2473             :                         else
    2474             :                         {
    2475             :                                 home_info_pressed = NO;
    2476             :                         }
    2477             :                         if ([self checkKeyPress:n_key_system_end])
    2478             :                         {
    2479             :                                 if (!target_info_pressed)
    2480             :                                 {
    2481             :                                         [self targetInfoSystem];
    2482             :                                         target_info_pressed = YES;
    2483             :                                 }
    2484             :                         }
    2485             :                         else
    2486             :                         {
    2487             :                                 target_info_pressed = NO;
    2488             :                         }
    2489             :                         break;
    2490             :                         
    2491             : #if OO_USE_CUSTOM_LOAD_SAVE
    2492             :                         // DJS: Farm off load/save screen options to LoadSave.m
    2493             :                 case GUI_SCREEN_LOAD:
    2494             :                 {
    2495             :                         NSString *commanderFile = [self commanderSelector];
    2496             :                         if(commanderFile)
    2497             :                         {
    2498             :                                 // also release the demo ship here (see showShipyardModel and noteGUIDidChangeFrom)
    2499             :                                 [demoShip release];
    2500             :                                 demoShip = nil;
    2501             :                                 
    2502             :                                 [self loadPlayerFromFile:commanderFile asNew:NO];
    2503             :                         }
    2504             :                         break;
    2505             :                 }
    2506             :                         
    2507             :                 case GUI_SCREEN_SAVE:
    2508             :                         [self pollGuiScreenControlsWithFKeyAlias:NO];
    2509             :                         /* Only F1 works for launch on this screen, not '1' or
    2510             :                          * whatever it has been bound to */
    2511             :                         if ([self checkKeyPress:n_key_launch_ship fKey_only:YES])  [self handleUndockControl];
    2512             :                         if (gui_screen == GUI_SCREEN_SAVE)
    2513             :                         {
    2514             :                                 [self saveCommanderInputHandler];
    2515             :                         }
    2516             :                         else pollControls = YES;
    2517             :                         break;
    2518             :                         
    2519             :                 case GUI_SCREEN_SAVE_OVERWRITE:
    2520             :                         [self overwriteCommanderInputHandler];
    2521             :                         break;
    2522             : #endif
    2523             :                         
    2524             :                 case GUI_SCREEN_STICKMAPPER:
    2525             :                         [self handleStickMapperScreenKeys];
    2526             :                         break;
    2527             :                 
    2528             :                 case GUI_SCREEN_STICKPROFILE:
    2529             :                         [self stickProfileInputHandler: gui view: gameView];
    2530             :                         break;
    2531             :                         
    2532             :                 case GUI_SCREEN_GAMEOPTIONS:
    2533             :                         [self handleGameOptionsScreenKeys];
    2534             :                         break;
    2535             : 
    2536             :                 case GUI_SCREEN_KEYBOARD:
    2537             :                         [self handleKeyMapperScreenKeys];
    2538             :                         //if ([gameView isDown:' '])
    2539             :                         //{
    2540             :                         //      [self setGuiToGameOptionsScreen];
    2541             :                         //}
    2542             :                         break;
    2543             : 
    2544             :                 case GUI_SCREEN_KEYBOARD_CONFIRMCLEAR:
    2545             :                         [self handleKeyMapperConfirmClearKeys:gui view:gameView];
    2546             :                         break;
    2547             : 
    2548             :                 case GUI_SCREEN_KEYBOARD_CONFIG:
    2549             :                         [self handleKeyConfigKeys:gui view:gameView];
    2550             :                         break;
    2551             : 
    2552             :                 case GUI_SCREEN_KEYBOARD_ENTRY:
    2553             :                         [self handleKeyConfigEntryKeys:gui view:gameView];
    2554             :                         break;
    2555             : 
    2556             :                 case GUI_SCREEN_KEYBOARD_LAYOUT:
    2557             :                         [self handleKeyboardLayoutKeys];
    2558             :                         break;
    2559             : 
    2560             :                 case GUI_SCREEN_SHIPLIBRARY:
    2561             :                         if ([gameView isDown:' '])      //  '<space>'
    2562             :                         {
    2563             :                                 // viewed in game, return to interfaces as that's where it's accessed from
    2564             :                                 [self setGuiToInterfacesScreen:0];
    2565             :                         }
    2566             :                         if ([self checkKeyPress:n_key_gui_arrow_up]) //  '<--'
    2567             :                         {
    2568             :                                 if (!upDownKeyPressed)
    2569             :                                         [UNIVERSE selectIntro2Previous];
    2570             :                         }
    2571             :                         if ([self checkKeyPress:n_key_gui_arrow_down]) //  '-->'
    2572             :                         {
    2573             :                                 if (!upDownKeyPressed)
    2574             :                                         [UNIVERSE selectIntro2Next];
    2575             :                         }
    2576             :                         upDownKeyPressed = (([self checkKeyPress:n_key_gui_arrow_up])||([self checkKeyPress:n_key_gui_arrow_down]));
    2577             : 
    2578             :                         if ([self checkKeyPress:n_key_gui_arrow_left]) //  '<--'
    2579             :                         {
    2580             :                                 if (!leftRightKeyPressed)
    2581             :                                         [UNIVERSE selectIntro2PreviousCategory];
    2582             :                         }
    2583             :                         if ([self checkKeyPress:n_key_gui_arrow_right]) //  '-->'
    2584             :                         {
    2585             :                                 if (!leftRightKeyPressed)
    2586             :                                         [UNIVERSE selectIntro2NextCategory];
    2587             :                         }
    2588             :                         leftRightKeyPressed = (([self checkKeyPress:n_key_gui_arrow_left])||([self checkKeyPress:n_key_gui_arrow_right]));
    2589             : 
    2590             :                         break;
    2591             :                 case GUI_SCREEN_OPTIONS:
    2592             :                         [self handleGUIUpDownArrowKeys];
    2593             :                         OOGUIRow guiSelectedRow = [gui selectedRow];
    2594             :                         BOOL selectKeyPress = ([self checkKeyPress:n_key_gui_select]||[gameView isDown:gvMouseDoubleClick]);
    2595             : 
    2596             :                         if (selectKeyPress)   // 'enter'
    2597             :                         {
    2598             :                                 if ((guiSelectedRow == GUI_ROW(,QUICKSAVE))&&(!disc_operation_in_progress))
    2599             :                                 {
    2600             :                                         @try
    2601             :                                         {
    2602             :                                                 disc_operation_in_progress = YES;
    2603             :                                                 [self quicksavePlayer];
    2604             :                                         }
    2605             :                                         @catch (NSException *exception)
    2606             :                                         {
    2607             :                                                 OOLog(kOOLogException, @"\n\n***** Handling exception: %@ : %@ *****\n\n",[exception name], [exception reason]);
    2608             :                                                 if ([[exception name] isEqual:@"GameNotSavedException"])      // try saving game instead
    2609             :                                                 {
    2610             :                                                         OOLog(kOOLogException, @"%@", @"\n\n***** Trying a normal save instead *****\n\n");
    2611             :                                                         if ([controller inFullScreenMode])
    2612             :                                                                 [controller pauseFullScreenModeToPerform:@selector(savePlayer) onTarget:self];
    2613             :                                                         else
    2614             :                                                                 [self savePlayer];
    2615             :                                                 }
    2616             :                                                 else
    2617             :                                                 {
    2618             :                                                         @throw exception;
    2619             :                                                 }
    2620             :                                         }
    2621             :                                 }
    2622             :                                 if ((guiSelectedRow == GUI_ROW(,SAVE))&&(!disc_operation_in_progress))
    2623             :                                 {
    2624             :                                         disc_operation_in_progress = YES;
    2625             :                                         [self savePlayer];
    2626             :                                 }
    2627             :                                 if ((guiSelectedRow == GUI_ROW(,LOAD))&&(!disc_operation_in_progress))
    2628             :                                 {
    2629             :                                         disc_operation_in_progress = YES;
    2630             :                                         if (![self loadPlayer])
    2631             :                                         {
    2632             :                                                 disc_operation_in_progress = NO;
    2633             :                                                 [self setGuiToStatusScreen];
    2634             :                                         }
    2635             :                                 }
    2636             :                                 
    2637             :                                 
    2638             :                                 if ((guiSelectedRow == GUI_ROW(,BEGIN_NEW))&&(!disc_operation_in_progress))
    2639             :                                 {
    2640             :                                         disc_operation_in_progress = YES;
    2641             :                                         [UNIVERSE setUseAddOns:SCENARIO_OXP_DEFINITION_ALL fromSaveGame:NO forceReinit:YES]; // calls reinitAndShowDemo
    2642             :                                 }
    2643             :                                 
    2644             :                                 if ([gameView isDown:gvMouseDoubleClick])
    2645             :                                         [gameView clearMouse];
    2646             :                         }
    2647             :                         else
    2648             :                         {
    2649             :                                 disc_operation_in_progress = NO;
    2650             :                         }
    2651             :                         
    2652             : #if OOLITE_SDL
    2653             :                         // quit only appears in GNUstep as users aren't
    2654             :                         // used to Cmd-Q equivs. Same goes for window
    2655             :                         // vs fullscreen.
    2656             :                         if ((guiSelectedRow == GUI_ROW(,QUIT)) && selectKeyPress)
    2657             :                         {
    2658             :                                 [[UNIVERSE gameController] exitAppWithContext:@"Exit Game selected on options screen"];
    2659             :                         }
    2660             : #endif
    2661             :                         
    2662             :                         if ((guiSelectedRow == GUI_ROW(,GAMEOPTIONS)) && selectKeyPress)
    2663             :                         {
    2664             :                                 [gameView clearKeys];
    2665             :                                 [self setGuiToGameOptionsScreen];
    2666             :                         }
    2667             :                         
    2668             :                         break;
    2669             :                         
    2670             :                 case GUI_SCREEN_EQUIP_SHIP:
    2671             :                         if ([self handleGUIUpDownArrowKeys])
    2672             :                         {
    2673             :                                 NSString                *itemText = [gui selectedRowText];
    2674             :                                 OOWeaponType            weaponType = nil;
    2675             :                                 
    2676             :                                 if ([itemText isEqual:FORWARD_FACING_STRING]) weaponType = forward_weapon_type;
    2677             :                                 if ([itemText isEqual:AFT_FACING_STRING]) weaponType = aft_weapon_type;
    2678             :                                 if ([itemText isEqual:PORT_FACING_STRING]) weaponType = port_weapon_type;
    2679             :                                 if ([itemText isEqual:STARBOARD_FACING_STRING]) weaponType = starboard_weapon_type;
    2680             :                                 
    2681             :                                 if (weaponType != nil)
    2682             :                                 {
    2683             :                                         BOOL            sameAs = OOWeaponTypeFromEquipmentIdentifierSloppy([gui selectedRowKey]) == weaponType;
    2684             :                                         // override showInformation _completely_ with itemText
    2685             :                                         if ([[weaponType identifier] isEqualToString:@"EQ_WEAPON_NONE"])  itemText = DESC(@"no-weapon-enter-to-install");
    2686             :                                         else
    2687             :                                         {
    2688             :                                                 NSString *weaponName = [[OOEquipmentType equipmentTypeWithIdentifier:OOEquipmentIdentifierFromWeaponType(weaponType)] name];
    2689             :                                                 if (sameAs)  itemText = [NSString stringWithFormat:DESC(@"weapon-installed-@"), weaponName];
    2690             :                                                 else  itemText = [NSString stringWithFormat:DESC(@"weapon-@-enter-to-replace"), weaponName];
    2691             :                                         }
    2692             :                                         
    2693             :                                         [self showInformationForSelectedUpgradeWithFormatString:itemText];
    2694             :                                 }
    2695             :                                 else
    2696             :                                         [self showInformationForSelectedUpgrade];
    2697             :                         }
    2698             :                         
    2699             :                         if ([self checkKeyPress:n_key_gui_arrow_left] || [self checkKeyPress:n_key_gui_page_up])
    2700             :                         {
    2701             :                                 if ((!leftRightKeyPressed)||(script_time > timeLastKeyPress + KEY_REPEAT_INTERVAL))
    2702             :                                 {
    2703             :                                         if ([[gui keyForRow:GUI_ROW_EQUIPMENT_START] hasPrefix:@"More:"])
    2704             :                                         {
    2705             :                                                 [self playMenuPagePrevious];
    2706             :                                                 [gui setSelectedRow:GUI_ROW_EQUIPMENT_START];
    2707             :                                                 [self buySelectedItem];
    2708             :                                         }
    2709             :                                         timeLastKeyPress = script_time;
    2710             :                                 }
    2711             :                         }
    2712             :                         if ([self checkKeyPress:n_key_gui_arrow_right] || [self checkKeyPress:n_key_gui_page_down])
    2713             :                         {
    2714             :                                 if ((!leftRightKeyPressed)||(script_time > timeLastKeyPress + KEY_REPEAT_INTERVAL))
    2715             :                                 {
    2716             :                                         if ([[gui keyForRow:GUI_ROW_EQUIPMENT_START + GUI_MAX_ROWS_EQUIPMENT - 1] hasPrefix:@"More:"])
    2717             :                                         {
    2718             :                                                 [self playMenuPageNext];
    2719             :                                                 [gui setSelectedRow:GUI_ROW_EQUIPMENT_START + GUI_MAX_ROWS_EQUIPMENT - 1];
    2720             :                                                 [self buySelectedItem];
    2721             :                                         }
    2722             :                                         timeLastKeyPress = script_time;
    2723             :                                 }
    2724             :                         }
    2725             :                         leftRightKeyPressed = [self checkKeyPress:n_key_gui_arrow_right]|[self checkKeyPress:n_key_gui_arrow_left]|[self checkKeyPress:n_key_gui_page_down]|[self checkKeyPress:n_key_gui_page_up];
    2726             : 
    2727             :                         if ([self checkKeyPress:n_key_gui_select] || [gameView isDown:gvMouseDoubleClick])
    2728             :                         {
    2729             :                                 if ([gameView isDown:gvMouseDoubleClick])
    2730             :                                 {
    2731             :                                         selectPressed = NO;
    2732             :                                         [gameView clearMouse];
    2733             :                                 }
    2734             :                                 if ((!selectPressed)&&([gui selectedRow] > -1))
    2735             :                                 {
    2736             :                                         [self buySelectedItem];
    2737             :                                         selectPressed = YES;
    2738             :                                 }
    2739             :                         }
    2740             :                         else
    2741             :                         {
    2742             :                                 selectPressed = NO;
    2743             :                         }
    2744             :                         break;
    2745             :                         
    2746             :                 case GUI_SCREEN_INTERFACES:
    2747             :                         if ([self handleGUIUpDownArrowKeys])
    2748             :                         {
    2749             :                                 [self showInformationForSelectedInterface];
    2750             :                         }
    2751             :                         if ([self checkKeyPress:n_key_gui_arrow_left] || [self checkKeyPress:n_key_gui_page_up])
    2752             :                         {
    2753             :                                 if ((!leftRightKeyPressed)||(script_time > timeLastKeyPress + KEY_REPEAT_INTERVAL))
    2754             :                                 {
    2755             :                                         if ([[gui keyForRow:GUI_ROW_INTERFACES_START] hasPrefix:@"More:"])
    2756             :                                         {
    2757             :                                                 [self playMenuPagePrevious];
    2758             :                                                 [gui setSelectedRow:GUI_ROW_INTERFACES_START];
    2759             :                                                 [self activateSelectedInterface];
    2760             :                                         }
    2761             :                                         timeLastKeyPress = script_time;
    2762             :                                 }
    2763             :                         }
    2764             :                         if ([self checkKeyPress:n_key_gui_arrow_right] || [self checkKeyPress:n_key_gui_page_down])
    2765             :                         {
    2766             :                                 if ((!leftRightKeyPressed)||(script_time > timeLastKeyPress + KEY_REPEAT_INTERVAL))
    2767             :                                 {
    2768             :                                         if ([[gui keyForRow:GUI_ROW_INTERFACES_START + GUI_MAX_ROWS_INTERFACES - 1] hasPrefix:@"More:"])
    2769             :                                         {
    2770             :                                                 [self playMenuPageNext];
    2771             :                                                 [gui setSelectedRow:GUI_ROW_INTERFACES_START + GUI_MAX_ROWS_INTERFACES - 1];
    2772             :                                                 [self activateSelectedInterface];
    2773             :                                         }
    2774             :                                         timeLastKeyPress = script_time;
    2775             :                                 }
    2776             :                         }
    2777             :                         leftRightKeyPressed = [self checkKeyPress:n_key_gui_arrow_right]|[self checkKeyPress:n_key_gui_arrow_left]|[self checkKeyPress:n_key_gui_page_down]|[self checkKeyPress:n_key_gui_page_up];
    2778             :                         if ([self checkKeyPress:n_key_gui_select] || [gameView isDown:gvMouseDoubleClick])   // 'enter'
    2779             :                         {
    2780             :                                 if ([gameView isDown:gvMouseDoubleClick])
    2781             :                                 {
    2782             :                                         selectPressed = NO;
    2783             :                                         [gameView clearMouse];
    2784             :                                 }
    2785             :                                 if ((!selectPressed)&&([gui selectedRow] > -1))
    2786             :                                 {
    2787             :                                         [self activateSelectedInterface];
    2788             :                                         selectPressed = YES;
    2789             :                                 }
    2790             :                         }
    2791             :                         else
    2792             :                         {
    2793             :                                 selectPressed = NO;
    2794             :                         }
    2795             :                         break;
    2796             : 
    2797             : 
    2798             :                 case GUI_SCREEN_MARKETINFO:
    2799             :                         [self pollMarketScreenControls];
    2800             :                         break;
    2801             : 
    2802             :                 case GUI_SCREEN_MARKET:
    2803             :                         [self pollMarketScreenControls];
    2804             : 
    2805             :                         if ([self checkKeyPress:n_key_market_filter_cycle] || [self checkKeyPress:n_key_market_sorter_cycle])
    2806             :                         {
    2807             :                                 if (!queryPressed)
    2808             :                                 {
    2809             :                                         queryPressed = YES;
    2810             :                                         if ([self checkKeyPress:n_key_market_filter_cycle])
    2811             :                                         {
    2812             :                                                 if (marketFilterMode >= MARKET_FILTER_MODE_MAX)
    2813             :                                                 {
    2814             :                                                         marketFilterMode = MARKET_FILTER_MODE_OFF;
    2815             :                                                 }
    2816             :                                                 else
    2817             :                                                 {
    2818             :                                                         marketFilterMode++;
    2819             :                                                 }
    2820             :                                         }
    2821             :                                         else
    2822             :                                         {
    2823             :                                                 if (marketSorterMode >= MARKET_SORTER_MODE_MAX)
    2824             :                                                 {
    2825             :                                                         marketSorterMode = MARKET_SORTER_MODE_OFF;
    2826             :                                                 }
    2827             :                                                 else
    2828             :                                                 {
    2829             :                                                         marketSorterMode++;
    2830             :                                                 }
    2831             :                                         }
    2832             :                                         [self playChangedOption];
    2833             :                                         [self setGuiToMarketScreen];
    2834             :                                 }
    2835             :                         } 
    2836             :                         else
    2837             :                         {
    2838             :                                 queryPressed = NO;
    2839             :                         }
    2840             : 
    2841             :                         break;
    2842             :                         
    2843             :                 case GUI_SCREEN_REPORT:
    2844             :                         if ([gameView isDown:32])       // spacebar
    2845             :                         {
    2846             :                                 if (!spacePressed)
    2847             :                                 {
    2848             :                                         BOOL reportEnded = ([dockingReport length] == 0);
    2849             :                                         [self playDismissedReportScreen];
    2850             :                                         if(reportEnded)
    2851             :                                         {
    2852             :                                                 [self setGuiToStatusScreen];
    2853             :                                                 [self doScriptEvent:OOJSID("reportScreenEnded")];  // last report given. Screen is now free for missionscreens.
    2854             :                                                 [self doWorldEventUntilMissionScreen:OOJSID("missionScreenOpportunity")];
    2855             :                                         }
    2856             :                                         else
    2857             :                                         {
    2858             :                                                 [self setGuiToDockingReportScreen];
    2859             :                                         }
    2860             : 
    2861             :                                 }
    2862             :                                 spacePressed = YES;
    2863             :                         }
    2864             :                         else
    2865             :                                 spacePressed = NO;
    2866             :                         break;
    2867             :                 case GUI_SCREEN_STATUS:
    2868             :                         [self handleGUIUpDownArrowKeys];
    2869             :                         if ([self checkKeyPress:n_key_gui_arrow_left] || [self checkKeyPress:n_key_gui_page_up])
    2870             :                         {
    2871             : 
    2872             :                                 if ((!leftRightKeyPressed)||(script_time > timeLastKeyPress + KEY_REPEAT_INTERVAL))
    2873             :                                 {
    2874             :                                         if ([[gui keyForRow:STATUS_EQUIPMENT_FIRST_ROW] isEqual:GUI_KEY_OK])
    2875             :                                         {
    2876             :                                                 [gui setSelectedRow:STATUS_EQUIPMENT_FIRST_ROW];
    2877             :                                                 [self playMenuPagePrevious];
    2878             :                                                 [gui setStatusPage:-1];
    2879             :                                                 [self setGuiToStatusScreen];
    2880             :                                         }
    2881             :                                         timeLastKeyPress = script_time;
    2882             :                                 }
    2883             :                         }
    2884             :                         if ([self checkKeyPress:n_key_gui_arrow_right] || [self checkKeyPress:n_key_gui_page_down])
    2885             :                         {
    2886             : 
    2887             :                                 if ((!leftRightKeyPressed)||(script_time > timeLastKeyPress + KEY_REPEAT_INTERVAL))
    2888             :                                 {
    2889             :                                         NSUInteger maxRows = [[self hud] allowBigGui] ? STATUS_EQUIPMENT_MAX_ROWS + STATUS_EQUIPMENT_BIGGUI_EXTRA_ROWS : STATUS_EQUIPMENT_MAX_ROWS;
    2890             :                                         if ([[gui keyForRow:STATUS_EQUIPMENT_FIRST_ROW + maxRows] isEqual:GUI_KEY_OK])
    2891             :                                         {
    2892             :                                                 [gui setSelectedRow:STATUS_EQUIPMENT_FIRST_ROW + maxRows];
    2893             :                                                 [self playMenuPageNext];
    2894             :                                                 [gui setStatusPage:+1];
    2895             :                                                 [self setGuiToStatusScreen];
    2896             :                                         }
    2897             :                                         timeLastKeyPress = script_time;
    2898             :                                 }
    2899             :                         }
    2900             :                         leftRightKeyPressed = [self checkKeyPress:n_key_gui_arrow_right]|[self checkKeyPress:n_key_gui_arrow_left]|[self checkKeyPress:n_key_gui_page_down]|[self checkKeyPress:n_key_gui_page_up];
    2901             :                         
    2902             :                         if ([self checkKeyPress:n_key_gui_select] || [gameView isDown:gvMouseDoubleClick])
    2903             :                         {
    2904             :                                 if ([gameView isDown:gvMouseDoubleClick])
    2905             :                                 {
    2906             :                                         selectPressed = NO;
    2907             :                                         [gameView clearMouse];
    2908             :                                 }
    2909             :                                 if ((!selectPressed)&&([gui selectedRow] > -1))
    2910             :                                 {
    2911             :                                         [gui setStatusPage:([gui selectedRow] == STATUS_EQUIPMENT_FIRST_ROW ? -1 : +1)];
    2912             :                                         [self setGuiToStatusScreen];
    2913             : 
    2914             :                                         selectPressed = YES;
    2915             :                                 }
    2916             :                         }
    2917             :                         else
    2918             :                         {
    2919             :                                 selectPressed = NO;
    2920             :                         }
    2921             : 
    2922             :                         break;
    2923             :                 case GUI_SCREEN_MANIFEST:
    2924             :                         [self handleGUIUpDownArrowKeys];
    2925             :                         if ([self checkKeyPress:n_key_gui_arrow_left] || [self checkKeyPress:n_key_gui_page_up])
    2926             :                         {
    2927             : 
    2928             :                                 if ((!leftRightKeyPressed)||(script_time > timeLastKeyPress + KEY_REPEAT_INTERVAL))
    2929             :                                 {
    2930             :                                         if ([[gui keyForRow:MANIFEST_SCREEN_ROW_BACK] isEqual:GUI_KEY_OK])
    2931             :                                         {
    2932             :                                                 [gui setSelectedRow:MANIFEST_SCREEN_ROW_BACK];
    2933             :                                                 [self playMenuPagePrevious];
    2934             :                                                 [gui setStatusPage:-1];
    2935             :                                                 [self setGuiToManifestScreen];
    2936             :                                         }
    2937             :                                         timeLastKeyPress = script_time;
    2938             :                                 }
    2939             :                         }
    2940             :                         if ([self checkKeyPress:n_key_gui_arrow_right] || [self checkKeyPress:n_key_gui_page_down])
    2941             :                         {
    2942             :                                 OOGUIRow nextRow = MANIFEST_SCREEN_ROW_NEXT;
    2943             :                                 if ([[self hud] isHidden] || [[self hud] allowBigGui])
    2944             :                                 {
    2945             :                                         nextRow += 7;
    2946             :                                 }
    2947             :                                 if ((!leftRightKeyPressed)||(script_time > timeLastKeyPress + KEY_REPEAT_INTERVAL))
    2948             :                                 {
    2949             :                                         if ([[gui keyForRow:nextRow] isEqual:GUI_KEY_OK])
    2950             :                                         {
    2951             :                                                 [gui setSelectedRow:nextRow];
    2952             :                                                 [self playMenuPageNext];
    2953             :                                                 [gui setStatusPage:+1];
    2954             :                                                 [self setGuiToManifestScreen];
    2955             :                                         }
    2956             :                                         timeLastKeyPress = script_time;
    2957             :                                 }
    2958             :                         }
    2959             :                         leftRightKeyPressed = [self checkKeyPress:n_key_gui_arrow_right]|[self checkKeyPress:n_key_gui_arrow_left]|[self checkKeyPress:n_key_gui_page_down]|[self checkKeyPress:n_key_gui_page_up];
    2960             :                         
    2961             :                         if ([self checkKeyPress:n_key_gui_select] || [gameView isDown:gvMouseDoubleClick])
    2962             :                         {
    2963             :                                 if ([gameView isDown:gvMouseDoubleClick])
    2964             :                                 {
    2965             :                                         selectPressed = NO;
    2966             :                                         [gameView clearMouse];
    2967             :                                 }
    2968             :                                 if ((!selectPressed)&&([gui selectedRow] > -1))
    2969             :                                 {
    2970             :                                         [gui setStatusPage:([gui selectedRow] == MANIFEST_SCREEN_ROW_BACK ? -1 : +1)];
    2971             :                                         [self setGuiToManifestScreen];
    2972             : 
    2973             :                                         selectPressed = YES;
    2974             :                                 }
    2975             :                         }
    2976             :                         else
    2977             :                         {
    2978             :                                 selectPressed = NO;
    2979             :                         }
    2980             : 
    2981             :                         break;
    2982             : 
    2983             :                 case GUI_SCREEN_SHIPYARD:
    2984             :                         if ([self handleGUIUpDownArrowKeys])
    2985             :                         {
    2986             :                                 [self showShipyardInfoForSelection];
    2987             :                         }
    2988             :                         
    2989             :                         if ([self checkKeyPress:n_key_gui_arrow_left] || [self checkKeyPress:n_key_gui_page_up])
    2990             :                         {
    2991             :                                 if ((!leftRightKeyPressed)||(script_time > timeLastKeyPress + KEY_REPEAT_INTERVAL))
    2992             :                                 {
    2993             :                                         if ([[gui keyForRow:GUI_ROW_SHIPYARD_START] hasPrefix:@"More:"])
    2994             :                                         {
    2995             :                                                 [self playMenuPagePrevious];
    2996             :                                                 [gui setSelectedRow:GUI_ROW_SHIPYARD_START];
    2997             :                                                 [self buySelectedShip];
    2998             :                                         }
    2999             :                                         timeLastKeyPress = script_time;
    3000             :                                 }
    3001             :                         }
    3002             :                         if ([self checkKeyPress:n_key_gui_arrow_right] || [self checkKeyPress:n_key_gui_page_down])
    3003             :                         {
    3004             :                                 if ((!leftRightKeyPressed)||(script_time > timeLastKeyPress + KEY_REPEAT_INTERVAL))
    3005             :                                 {
    3006             :                                         if ([[gui keyForRow:GUI_ROW_SHIPYARD_START + MAX_ROWS_SHIPS_FOR_SALE - 1] hasPrefix:@"More:"])
    3007             :                                         {
    3008             :                                                 [self playMenuPageNext];
    3009             :                                                 [gui setSelectedRow:GUI_ROW_SHIPYARD_START + MAX_ROWS_SHIPS_FOR_SALE - 1];
    3010             :                                                 [self buySelectedShip];
    3011             :                                         }
    3012             :                                         timeLastKeyPress = script_time;
    3013             :                                 }
    3014             :                         }
    3015             :                         leftRightKeyPressed = [self checkKeyPress:n_key_gui_arrow_right]|[self checkKeyPress:n_key_gui_arrow_left]|[self checkKeyPress:n_key_gui_page_down]|[self checkKeyPress:n_key_gui_page_up];
    3016             :                         
    3017             :                         if ([self checkKeyPress:n_key_gui_select]) // 'enter' NOT double-click
    3018             :                         {
    3019             :                                 if (!selectPressed)
    3020             :                                 {
    3021             :                                         // try to buy the ship!
    3022             :                                         NSString *key = [gui keyForRow:[gui selectedRow]];
    3023             :                                         OOCreditsQuantity shipprice = 0;
    3024             :                                         if (![key hasPrefix:@"More:"])
    3025             :                                         {
    3026             :                                                 shipprice = [self priceForShipKey:key];
    3027             :                                         }
    3028             : 
    3029             :                                         if ([self buySelectedShip])
    3030             :                                         {
    3031             :                                                 if (![key hasPrefix:@"More:"]) // don't do anything if we clicked/selected a "More:" line
    3032             :                                                 {
    3033             :                                                         [UNIVERSE removeDemoShips];
    3034             :                                                         [self setGuiToStatusScreen];
    3035             :                                                         [self playBuyShip];
    3036             :                                                         [self doScriptEvent:OOJSID("playerBoughtNewShip") withArgument:self andArgument:[NSNumber numberWithUnsignedLongLong:shipprice]]; // some equipment.oxp might want to know everything has changed.
    3037             :                                                 }
    3038             :                                         }
    3039             :                                         else
    3040             :                                         {
    3041             :                                                 [self playCantBuyShip];
    3042             :                                         }
    3043             :                                 }
    3044             :                                 selectPressed = YES;
    3045             :                         }
    3046             :                         else
    3047             :                         {
    3048             :                                 selectPressed = NO;
    3049             :                         }
    3050             :                         if ([gameView isDown:gvMouseDoubleClick])
    3051             :                         {
    3052             :                                 if (([gui selectedRow] == GUI_ROW_SHIPYARD_START + MAX_ROWS_SHIPS_FOR_SALE - 1) && [[gui keyForRow:GUI_ROW_SHIPYARD_START + MAX_ROWS_SHIPS_FOR_SALE - 1] hasPrefix:@"More:"])
    3053             :                                 {
    3054             :                                         [self playMenuPageNext];
    3055             :                                         [gui setSelectedRow:GUI_ROW_SHIPYARD_START + MAX_ROWS_SHIPS_FOR_SALE - 1];
    3056             :                                         [self buySelectedShip];
    3057             :                                 }
    3058             :                                 else if (([gui selectedRow] == GUI_ROW_SHIPYARD_START) && [[gui keyForRow:GUI_ROW_SHIPYARD_START] hasPrefix:@"More:"])
    3059             :                                 {
    3060             :                                         [self playMenuPagePrevious];
    3061             :                                         [gui setSelectedRow:GUI_ROW_SHIPYARD_START];
    3062             :                                         [self buySelectedShip];
    3063             :                                 }
    3064             :                                 [gameView clearMouse];
    3065             :                         }
    3066             : 
    3067             :                         break;
    3068             :                         
    3069             :                 default:
    3070             :                         break;
    3071             :         }
    3072             : 
    3073             :         // check for any extra keys added by scripting
    3074             :         NSArray *keys = [extraGuiScreenKeys objectForKey:[NSString stringWithFormat:@"%d", gui_screen]];
    3075             :         if (keys) {
    3076             :                 NSInteger kc = [keys count];
    3077             :                 OOJSGuiScreenKeyDefinition *definition = nil;
    3078             :                 NSDictionary *keydefs = nil;
    3079             :                 NSString *key = nil;
    3080             :                 while (kc--) {
    3081             :                         definition = [keys objectAtIndex:kc];
    3082             :                         keydefs = [definition registerKeys];
    3083             :                         foreach (key, [keydefs allKeys])
    3084             :                         {
    3085             :                                 if ([self checkKeyPress:[keydefs objectForKey:key]]) 
    3086             :                                 {
    3087             :                                         if (!extra_gui_key_pressed) 
    3088             :                                         {
    3089             :                                                 // do callback
    3090             :                                                 if (definition)
    3091             :                                                 {
    3092             :                                                         [[UNIVERSE gameView] clearKeys];
    3093             :                                                         [definition runCallback:key];
    3094             :                                                 }
    3095             :                                                 else
    3096             :                                                 {
    3097             :                                                         OOLog(@"interface.missingCallback", @"Unable to find callback definition for %@ using key %@", [definition name], key);
    3098             :                                                 }
    3099             :                                         }
    3100             :                                         extra_gui_key_pressed = YES;
    3101             :                                 }
    3102             :                                 else
    3103             :                                         extra_gui_key_pressed = NO;
    3104             :                         }
    3105             :                 }
    3106             :         }
    3107             : 
    3108             :         // damp any rotations we entered with
    3109             :         if (flightRoll > 0.0)
    3110             :         {
    3111             :                 if (flightRoll > delta_t)            [self decrease_flight_roll:delta_t];
    3112             :                 else    flightRoll = 0.0;
    3113             :         }
    3114             :         if (flightRoll < 0.0)
    3115             :         {
    3116             :                 if (flightRoll < -delta_t)           [self increase_flight_roll:delta_t];
    3117             :                 else    flightRoll = 0.0;
    3118             :         }
    3119             :         if (flightPitch > 0.0)
    3120             :         {
    3121             :                 if (flightPitch > delta_t)           [self decrease_flight_pitch:delta_t];
    3122             :                 else    flightPitch = 0.0;
    3123             :         }
    3124             :         if (flightPitch < 0.0)
    3125             :         {
    3126             :                 if (flightPitch < -delta_t)          [self increase_flight_pitch:delta_t];
    3127             :                 else    flightPitch = 0.0;
    3128             :         }
    3129             :         if (flightYaw > 0.0) 
    3130             :         { 
    3131             :                 if (flightYaw > delta_t)             [self decrease_flight_yaw:delta_t]; 
    3132             :                 else    flightYaw = 0.0; 
    3133             :         } 
    3134             :         if (flightYaw < 0.0) 
    3135             :         { 
    3136             :                 if (flightYaw < -delta_t)            [self increase_flight_yaw:delta_t]; 
    3137             :                 else    flightYaw = 0.0; 
    3138             :         } 
    3139             : }
    3140             : 
    3141             : 
    3142             : - (void) pollMarketScreenControls
    3143             : {
    3144             :         MyOpenGLView    *gameView = [UNIVERSE gameView];
    3145             :         GuiDisplayGen   *gui = [UNIVERSE gui];
    3146             : 
    3147             :         if (gui_screen == GUI_SCREEN_MARKET)
    3148             :         {
    3149             :                 [self handleGUIUpDownArrowKeys];
    3150             :                 DESTROY(marketSelectedCommodity);
    3151             :                 marketSelectedCommodity = [[gui selectedRowKey] retain];
    3152             : 
    3153             :                 BOOL                    page_up = [self checkKeyPress:n_key_gui_page_up]; 
    3154             :                 BOOL                    page_down = [self checkKeyPress:n_key_gui_page_down]; 
    3155             :                 if (page_up || page_down) 
    3156             :                 {
    3157             :                         if ((!pageUpDownKeyPressed) || (script_time > timeLastKeyPress + KEY_REPEAT_INTERVAL))
    3158             :                         {
    3159             :                                 OOCommodityMarket       *localMarket = [self localMarket];
    3160             :                                 NSArray                         *goods = [self applyMarketSorter:[self applyMarketFilter:[localMarket goods] onMarket:localMarket] onMarket:localMarket];
    3161             :                                 if ([goods count] > 0)
    3162             :                                 {
    3163             :                                         NSInteger goodsIndex = [goods indexOfObject:marketSelectedCommodity];
    3164             :                                         NSInteger offset1 = 0;
    3165             :                                         NSInteger offset2 = 0;
    3166             :                                         if ([[gui keyForRow:GUI_ROW_MARKET_START] isEqualToString:@"<<<"] == true) offset1 += 1;
    3167             :                                         if ([[gui keyForRow:GUI_ROW_MARKET_LAST] isEqualToString:@">>>"] == true) offset2 += 1;
    3168             :                                         if (page_up)
    3169             :                                         {
    3170             :                                                 [self playMenuPagePrevious];
    3171             :                                                 // some edge cases
    3172             :                                                 if (goodsIndex - 16 <= 0) 
    3173             :                                                 {
    3174             :                                                         offset1 = 0;
    3175             :                                                         offset2 = 0;
    3176             :                                                 }
    3177             :                                                 if (offset1 == 1 && offset2 == 0 && goodsIndex < (NSInteger)[goods count] - 1 && goodsIndex - 15 > 0) offset2 = 1;
    3178             :                                                 goodsIndex -= (16 - (offset1 + offset2));
    3179             :                                                 if (goodsIndex < 0) goodsIndex = 0;
    3180             :                                                 if ([goods count] <= 17) goodsIndex = 0;
    3181             :                                         }
    3182             :                                         if (page_down) 
    3183             :                                         {
    3184             :                                                 [self playMenuPageNext];
    3185             :                                                 // some edge cases
    3186             :                                                 if (offset1 == 0 && offset2 == 1 && goodsIndex > 1) offset1 = 1;
    3187             :                                                 if (offset2 == 1 && goodsIndex + 15 == (NSInteger)[goods count] - 1) offset2 = 0;
    3188             :                                                 goodsIndex += (16 - (offset1 + offset2));
    3189             :                                                 if (goodsIndex > ((NSInteger)[goods count] - 1) || [goods count] <= 17) goodsIndex = (NSInteger)[goods count] - 1;
    3190             :                                         }
    3191             :                                         DESTROY(marketSelectedCommodity);
    3192             :                                         marketSelectedCommodity = [[goods oo_stringAtIndex:goodsIndex] retain];
    3193             :                                         [self setGuiToMarketScreen];
    3194             :                                 }
    3195             :                         } 
    3196             :                         pageUpDownKeyPressed = YES;
    3197             :                         timeLastKeyPress = script_time;
    3198             :                 }
    3199             :                 else {
    3200             :                         pageUpDownKeyPressed = NO;
    3201             :                 }
    3202             :         }
    3203             :         else
    3204             :         {
    3205             :                 // handle up and down slightly differently
    3206             :                 BOOL                    arrow_up = [self checkKeyPress:n_key_gui_arrow_up]; 
    3207             :                 BOOL                    arrow_down = [self checkKeyPress:n_key_gui_arrow_down]; 
    3208             :                 if (arrow_up || arrow_down)
    3209             :                 {
    3210             :                         if ((!upDownKeyPressed) || (script_time > timeLastKeyPress + KEY_REPEAT_INTERVAL))
    3211             :                         {
    3212             :                                 OOCommodityMarket       *localMarket = [self localMarket];
    3213             :                                 NSArray                         *goods = [self applyMarketSorter:[self applyMarketFilter:[localMarket goods] onMarket:localMarket] onMarket:localMarket];
    3214             :                                 if ([goods count] > 0)
    3215             :                                 {
    3216             :                                         NSInteger goodsIndex = [goods indexOfObject:marketSelectedCommodity];
    3217             :                                         if (arrow_down)
    3218             :                                         {
    3219             :                                                 ++goodsIndex;
    3220             :                                         }
    3221             :                                         else
    3222             :                                         {
    3223             :                                                 --goodsIndex;
    3224             :                                         }
    3225             :                                         if (goodsIndex < 0)
    3226             :                                         {
    3227             :                                                 goodsIndex = [goods count]-1;
    3228             :                                         }
    3229             :                                         else if (goodsIndex >= (NSInteger)[goods count])
    3230             :                                         {
    3231             :                                                 goodsIndex = 0;
    3232             :                                         }
    3233             :                                         DESTROY(marketSelectedCommodity);
    3234             :                                         marketSelectedCommodity = [[goods oo_stringAtIndex:goodsIndex] retain];
    3235             :                                         [self setGuiToMarketInfoScreen];
    3236             :                                 }
    3237             :                         }
    3238             :                         upDownKeyPressed = YES;
    3239             :                         timeLastKeyPress = script_time;
    3240             :                 }
    3241             :                 else
    3242             :                 {
    3243             :                         upDownKeyPressed = NO;
    3244             :                 }
    3245             :         }
    3246             : 
    3247             :         BOOL isdocked = [self isDocked];
    3248             : 
    3249             :         if (([self checkNavKeyPress:n_key_gui_arrow_right])||([self checkNavKeyPress:n_key_gui_arrow_left])||([self checkKeyPress:n_key_gui_select]||[gameView isDown:gvMouseDoubleClick]))
    3250             :         {
    3251             :                 if ([self checkNavKeyPress:n_key_gui_arrow_right])   // -->
    3252             :                 {
    3253             :                         if (!wait_for_key_up)
    3254             :                         {
    3255             :                                 if (isdocked && [self tryBuyingCommodity:marketSelectedCommodity all:[gameView isShiftDown]])
    3256             :                                 {
    3257             :                                         [self playBuyCommodity];
    3258             :                                         if (gui_screen == GUI_SCREEN_MARKET)
    3259             :                                         {
    3260             :                                                 [self setGuiToMarketScreen];
    3261             :                                         }
    3262             :                                         else
    3263             :                                         {
    3264             :                                                 [self setGuiToMarketInfoScreen];
    3265             :                                         }
    3266             :                                 }
    3267             :                                 else
    3268             :                                 {
    3269             :                                         if ([[gui selectedRowKey] isEqualToString:@">>>"])
    3270             :                                         {
    3271             :                                                 [self playMenuNavigationDown];
    3272             :                                                 [self setGuiToMarketScreen];
    3273             :                                         }
    3274             :                                         else if ([[gui selectedRowKey] isEqualToString:@"<<<"])
    3275             :                                         {
    3276             :                                                 [self playMenuNavigationUp];
    3277             :                                                 [self setGuiToMarketScreen];
    3278             :                                         }
    3279             :                                         else
    3280             :                                         {
    3281             :                                                 [self playCantBuyCommodity];
    3282             :                                         }
    3283             :                                 }
    3284             :                                 wait_for_key_up = YES;
    3285             :                         }
    3286             :                 }
    3287             :                 if ([self checkNavKeyPress:n_key_gui_arrow_left])   // <--
    3288             :                 {
    3289             :                         if (!wait_for_key_up)
    3290             :                         {
    3291             :                                 if (isdocked && [self trySellingCommodity:marketSelectedCommodity all:[gameView isShiftDown]])
    3292             :                                 {
    3293             :                                         [self playSellCommodity];
    3294             :                                         if (gui_screen == GUI_SCREEN_MARKET)
    3295             :                                         {
    3296             :                                                 [self setGuiToMarketScreen];
    3297             :                                         }
    3298             :                                         else
    3299             :                                         {
    3300             :                                                 [self setGuiToMarketInfoScreen];
    3301             :                                         }
    3302             :                                 }
    3303             :                                 else
    3304             :                                 {
    3305             :                                         if ([[gui selectedRowKey] isEqualToString:@">>>"])
    3306             :                                         {
    3307             :                                                 [self playMenuNavigationDown];
    3308             :                                                 [self setGuiToMarketScreen];
    3309             :                                         }
    3310             :                                         else if ([[gui selectedRowKey] isEqualToString:@"<<<"])
    3311             :                                         {
    3312             :                                                 [self playMenuNavigationUp];
    3313             :                                                 [self setGuiToMarketScreen];
    3314             :                                         }
    3315             :                                         else
    3316             :                                         {
    3317             :                                                 [self playCantSellCommodity];
    3318             :                                         }
    3319             : 
    3320             :                                 }
    3321             :                                 wait_for_key_up = YES;
    3322             :                         }
    3323             :                 }
    3324             :                 if ((gui_screen == GUI_SCREEN_MARKET && [gameView isDown:gvMouseDoubleClick]) || [self checkKeyPress:n_key_gui_select])   // 'enter'
    3325             :                 {
    3326             :                         if ([gameView isDown:gvMouseDoubleClick])
    3327             :                         {
    3328             :                                 wait_for_key_up = NO;
    3329             :                                 [gameView clearMouse];
    3330             :                         }
    3331             :                         if (!wait_for_key_up)
    3332             :                         {
    3333             :                                 OOCommodityType item = marketSelectedCommodity;
    3334             :                                 OOCargoQuantity yours = [shipCommodityData quantityForGood:item];
    3335             :                                 if ([item isEqualToString:@">>>"])
    3336             :                                 {
    3337             :                                         [self tryBuyingCommodity:item all:YES];
    3338             :                                         [self setGuiToMarketScreen];
    3339             :                                 }
    3340             :                                 else if ([item isEqualToString:@"<<<"])
    3341             :                                 {
    3342             :                                         [self trySellingCommodity:item all:YES];
    3343             :                                         [self setGuiToMarketScreen];
    3344             :                                 }
    3345             :                                 else if (isdocked && [gameView isShiftDown] && [self tryBuyingCommodity:item all:YES])  // buy as much as possible (with Shift)
    3346             :                                 {
    3347             :                                         [self playBuyCommodity];
    3348             :                                         if (gui_screen == GUI_SCREEN_MARKET)
    3349             :                                         {
    3350             :                                                 [self setGuiToMarketScreen];
    3351             :                                         }
    3352             :                                         else
    3353             :                                         {
    3354             :                                                 [self setGuiToMarketInfoScreen];
    3355             :                                         }
    3356             :                                 }
    3357             :                                 else if (isdocked && (yours > 0) && [self trySellingCommodity:item all:YES]) // sell all you can
    3358             :                                 {
    3359             :                                         [self playSellCommodity];
    3360             :                                         if (gui_screen == GUI_SCREEN_MARKET)
    3361             :                                         {
    3362             :                                                 [self setGuiToMarketScreen];
    3363             :                                         }
    3364             :                                         else
    3365             :                                         {
    3366             :                                                 [self setGuiToMarketInfoScreen];
    3367             :                                         }
    3368             :                                 }
    3369             :                                 else if (isdocked && [self tryBuyingCommodity:item all:YES])                    // buy as much as possible
    3370             :                                 {
    3371             :                                         [self playBuyCommodity];
    3372             :                                         if (gui_screen == GUI_SCREEN_MARKET)
    3373             :                                         {
    3374             :                                                 [self setGuiToMarketScreen];
    3375             :                                         }
    3376             :                                         else
    3377             :                                         {
    3378             :                                                 [self setGuiToMarketInfoScreen];
    3379             :                                         }
    3380             :                                 }
    3381             :                                 else if (isdocked)
    3382             :                                 {
    3383             :                                         [self playCantBuyCommodity];
    3384             :                                 }
    3385             :                                 wait_for_key_up = YES;
    3386             :                         }
    3387             :                 }
    3388             :         }
    3389             :         else
    3390             :         {
    3391             :                 wait_for_key_up = NO;
    3392             :         }
    3393             : 
    3394             : 
    3395             :  
    3396             : 
    3397             : }
    3398             : 
    3399             : - (void) handleGameOptionsScreenKeys
    3400             : {
    3401             :         MyOpenGLView            *gameView = [UNIVERSE gameView];
    3402             :         GuiDisplayGen           *gui = [UNIVERSE gui];
    3403             :         GUI_ROW_INIT(gui);
    3404             :         
    3405             :         [self handleGUIUpDownArrowKeys];
    3406             :         OOGUIRow guiSelectedRow = [gui selectedRow];
    3407             :         BOOL selectKeyPress = ([self checkKeyPress:n_key_gui_select]||[gameView isDown:gvMouseDoubleClick]);
    3408             :         if ([gameView isDown:gvMouseDoubleClick])  [gameView clearMouse];
    3409             :         
    3410             :         if ((guiSelectedRow == GUI_ROW(GAME,STICKMAPPER)) && selectKeyPress)
    3411             :         {
    3412             :                 selFunctionIdx = 0;
    3413             :                 [self resetStickFunctions]; // reset the list of stick functions, so changes in oxp equipment are reflected
    3414             :                 [self setGuiToStickMapperScreen: 0 resetCurrentRow: YES];
    3415             :         }
    3416             :         if ((guiSelectedRow == GUI_ROW(GAME,KEYMAPPER)) && selectKeyPress)
    3417             :         {
    3418             :                 selFunctionIdx = 0;
    3419             :                 [self resetKeyFunctions]; // reset the list of key functions, so changes in oxp equipment are reflected
    3420             :                 [self setGuiToKeyMapperScreen: 0 resetCurrentRow: YES];
    3421             :         }
    3422             :         
    3423             :         
    3424             : #if OOLITE_WINDOWS
    3425             :         if ([gameView hdrOutput])
    3426             :         {
    3427             :                 if ((guiSelectedRow == GUI_ROW(GAME,HDRMAXBRIGHTNESS))&&(([self checkKeyPress:n_key_gui_arrow_right])||([self checkKeyPress:n_key_gui_arrow_left])))
    3428             :                 {
    3429             :                         if (!hdrMaxBrightnessControlPressed)
    3430             :                         {
    3431             :                                 int                     direction = ([self checkKeyPress:n_key_gui_arrow_right]) ? 1 : -1;
    3432             :                                 NSArray         *brightnesses = [[UNIVERSE descriptions] oo_arrayForKey: @"hdr_maxBrightness_array"];
    3433             :                                 int                     brightnessIdx = [brightnesses indexOfObject:[NSString stringWithFormat:@"%d", (int)[gameView hdrMaxBrightness]]];
    3434             :                                 
    3435             :                                 if (brightnessIdx == NSNotFound)
    3436             :                                 {
    3437             :                                         OOLogWARN(@"hdr.maxBrightness.notFound", @"%@", @"couldn't find current max brightness setting, switching to lowest.");
    3438             :                                         brightnessIdx = 0;
    3439             :                                 }
    3440             :                                 
    3441             :                                 brightnessIdx += direction;
    3442             :                                 int count = [brightnesses count];
    3443             :                                 if (brightnessIdx < 0)
    3444             :                                         brightnessIdx = count - 1;
    3445             :                                 if (brightnessIdx >= count)
    3446             :                                         brightnessIdx = 0;
    3447             :                                 
    3448             :                                 int brightnessValue = [brightnesses oo_intAtIndex:brightnessIdx];
    3449             :                                 
    3450             :                                 // warp if the value we got is out of expected limits; can be the case if user has
    3451             :                                 // manually modified the hdr_maxBrightness_array in descriptions.plist
    3452             :                                 if (brightnessValue < MIN_HDR_MAXBRIGHTNESS)  brightnessValue = direction == -1 ? MAX_HDR_MAXBRIGHTNESS : MIN_HDR_MAXBRIGHTNESS;
    3453             :                                 if (brightnessValue > MAX_HDR_MAXBRIGHTNESS)  brightnessValue = direction == 1 ? MIN_HDR_MAXBRIGHTNESS : MAX_HDR_MAXBRIGHTNESS;
    3454             :                                 
    3455             :                                 [gameView setHDRMaxBrightness:(float)brightnessValue];
    3456             :                                 NSString *maxBrightnessString = OOExpandKey(@"gameoptions-hdr-maxbrightness", brightnessValue);
    3457             :                                                                                                                                                                 
    3458             :                                 [gui setText:maxBrightnessString forRow:GUI_ROW(GAME,HDRMAXBRIGHTNESS)  align:GUI_ALIGN_CENTER];
    3459             :                                 
    3460             :                                 hdrMaxBrightnessControlPressed = YES;
    3461             :                         }
    3462             :                 }
    3463             :                 else
    3464             :                         hdrMaxBrightnessControlPressed = NO;
    3465             :         }
    3466             : #endif
    3467             :         
    3468             :         
    3469             : #if OO_RESOLUTION_OPTION
    3470             :         if (!switching_resolution &&
    3471             :                 guiSelectedRow == GUI_ROW(GAME,DISPLAY) &&
    3472             :                 ([self checkKeyPress:n_key_gui_arrow_right] || [self checkKeyPress:n_key_gui_arrow_left]))
    3473             :         {
    3474             :                 GameController  *controller = [UNIVERSE gameController];
    3475             :                 int                             direction = ([self checkKeyPress:n_key_gui_arrow_right]) ? 1 : -1;
    3476             :                 NSInteger               displayModeIndex = [controller indexOfCurrentDisplayMode];
    3477             :                 NSArray                 *modes = [controller displayModes];
    3478             :                 
    3479             :                 if (displayModeIndex == (NSInteger)NSNotFound)
    3480             :                 {
    3481             :                         OOLogWARN(@"graphics.mode.notFound", @"%@", @"couldn't find current fullscreen setting, switching to default.");
    3482             :                         displayModeIndex = 0;
    3483             :                 }
    3484             :                 
    3485             :                 displayModeIndex = displayModeIndex + direction;
    3486             :                 int count = [modes count];
    3487             :                 if (displayModeIndex < 0)
    3488             :                         displayModeIndex = count - 1;
    3489             :                 if (displayModeIndex >= count)
    3490             :                         displayModeIndex = 0;
    3491             :                 
    3492             :                 NSDictionary    *mode = [modes objectAtIndex:displayModeIndex];
    3493             :                 int modeWidth = [mode oo_intForKey:kOODisplayWidth];
    3494             :                 int modeHeight = [mode oo_intForKey:kOODisplayHeight];
    3495             :                 int modeRefresh = [mode oo_intForKey:kOODisplayRefreshRate];
    3496             :                 [controller setDisplayWidth:modeWidth Height:modeHeight Refresh:modeRefresh];
    3497             : 
    3498             :                 NSString *displayModeString = [self screenModeStringForWidth:modeWidth height:modeHeight refreshRate:modeRefresh];
    3499             :                 
    3500             :                 [self playChangedOption];
    3501             :                 [gui setText:displayModeString  forRow:GUI_ROW(GAME,DISPLAY)  align:GUI_ALIGN_CENTER];
    3502             :                 switching_resolution = YES;
    3503             :                 
    3504             : #if OOLITE_SDL
    3505             :                 /*      TODO: The gameView for the SDL game currently holds and
    3506             :                  sets the actual screen resolution (controller just stores
    3507             :                  it). This probably ought to change. */
    3508             :                 [gameView setScreenSize: displayModeIndex]; // changes fullscreen mode immediately
    3509             : #endif
    3510             :         }
    3511             :         if (switching_resolution && ![self checkKeyPress:n_key_gui_arrow_right] && ![self checkKeyPress:n_key_gui_arrow_left] && !selectKeyPress)
    3512             :         {
    3513             :                 switching_resolution = NO;
    3514             :         }
    3515             : #endif  // OO_RESOLUTION_OPTION
    3516             :         
    3517             : #if OOLITE_SPEECH_SYNTH
    3518             : 
    3519             :         if ((guiSelectedRow == GUI_ROW(GAME,SPEECH))&&(([self checkKeyPress:n_key_gui_arrow_right])||([self checkKeyPress:n_key_gui_arrow_left])))
    3520             :         {
    3521             :                 if (!speech_settings_pressed)
    3522             :                 {
    3523             :                         if ([self checkKeyPress:n_key_gui_arrow_right] && isSpeechOn < OOSPEECHSETTINGS_ALL)
    3524             :                         {
    3525             :                                 ++isSpeechOn;
    3526             :                                 [self playChangedOption];
    3527             :                                 speech_settings_pressed = YES;
    3528             :                         }
    3529             :                         else if ([self checkKeyPress:n_key_gui_arrow_left] && isSpeechOn > OOSPEECHSETTINGS_OFF)
    3530             :                         {
    3531             :                                 speech_settings_pressed = YES;
    3532             :                                 --isSpeechOn;
    3533             :                                 [self playChangedOption];
    3534             :                         }
    3535             :                         if (speech_settings_pressed)
    3536             :                         {
    3537             :                                 NSString *message = nil;
    3538             :                                 switch (isSpeechOn)
    3539             :                                 {
    3540             :                                 case OOSPEECHSETTINGS_OFF:
    3541             :                                         message = DESC(@"gameoptions-spoken-messages-no");
    3542             :                                         break;
    3543             :                                 case OOSPEECHSETTINGS_COMMS:
    3544             :                                         message = DESC(@"gameoptions-spoken-messages-comms");
    3545             :                                         break;
    3546             :                                 case OOSPEECHSETTINGS_ALL:
    3547             :                                         message = DESC(@"gameoptions-spoken-messages-yes");
    3548             :                                         break;
    3549             :                                 }
    3550             :                                 [gui setText:message forRow:GUI_ROW(GAME,SPEECH) align:GUI_ALIGN_CENTER];
    3551             : 
    3552             :                                 if (isSpeechOn == OOSPEECHSETTINGS_ALL)
    3553             :                                 {
    3554             :                                         [UNIVERSE stopSpeaking];
    3555             :                                         [UNIVERSE startSpeakingString:message];
    3556             :                                 }
    3557             :                         }
    3558             :                 }
    3559             :         }
    3560             :         else
    3561             :         {
    3562             :                 speech_settings_pressed = NO;
    3563             :         }
    3564             : #if OOLITE_ESPEAK
    3565             :         if (guiSelectedRow == GUI_ROW(GAME,SPEECH_LANGUAGE))
    3566             :         {
    3567             :                 if ([self checkKeyPress:n_key_gui_arrow_right] || [self checkKeyPress:n_key_gui_arrow_left])
    3568             :                 {
    3569             :                         if (!speechVoiceSelectKeyPressed || script_time > timeLastKeyPress + KEY_REPEAT_INTERVAL)
    3570             :                         {
    3571             :                                 [self playChangedOption];
    3572             :                                 if ([self checkKeyPress:n_key_gui_arrow_right])
    3573             :                                         voice_no = [UNIVERSE nextVoice: voice_no];
    3574             :                                 else
    3575             :                                         voice_no = [UNIVERSE prevVoice: voice_no];
    3576             :                                 [UNIVERSE setVoice: voice_no withGenderM:voice_gender_m];
    3577             :                                 NSString *voiceName = [UNIVERSE voiceName:voice_no];
    3578             :                                 NSString *message = OOExpandKey(@"gameoptions-voice-name", voiceName);
    3579             :                                 [gui setText:message forRow:GUI_ROW(GAME,SPEECH_LANGUAGE) align:GUI_ALIGN_CENTER];
    3580             :                                 if (isSpeechOn == OOSPEECHSETTINGS_ALL)
    3581             :                                 {
    3582             :                                         [UNIVERSE stopSpeaking];
    3583             :                                         [UNIVERSE startSpeakingString:[UNIVERSE voiceName: voice_no]];
    3584             :                                 }
    3585             :                                 timeLastKeyPress = script_time;
    3586             :                         }
    3587             :                         speechVoiceSelectKeyPressed = YES;
    3588             :                 }
    3589             :                 else
    3590             :                         speechVoiceSelectKeyPressed = NO;
    3591             :         }
    3592             : 
    3593             :         if (guiSelectedRow == GUI_ROW(GAME,SPEECH_GENDER))
    3594             :         {
    3595             :                 if ([self checkKeyPress:n_key_gui_arrow_right] || [self checkKeyPress:n_key_gui_arrow_left])
    3596             :                 {
    3597             :                         if (!speechGenderSelectKeyPressed)
    3598             :                         {
    3599             :                                 [self playChangedOption];
    3600             :                                 BOOL m = [self checkKeyPress:n_key_gui_arrow_right];
    3601             :                                 if (m != voice_gender_m)
    3602             :                                 {
    3603             :                                         voice_gender_m = m;
    3604             :                                         [UNIVERSE setVoice:voice_no withGenderM:voice_gender_m];
    3605             :                                         NSString *message = [NSString stringWithFormat:DESC(voice_gender_m ? @"gameoptions-voice-M" : @"gameoptions-voice-F")];
    3606             :                                         [gui setText:message forRow:GUI_ROW(GAME,SPEECH_GENDER) align:GUI_ALIGN_CENTER];
    3607             :                                         if (isSpeechOn == OOSPEECHSETTINGS_ALL)
    3608             :                                         {
    3609             :                                                 [UNIVERSE stopSpeaking];
    3610             :                                                 [UNIVERSE startSpeakingString:[UNIVERSE voiceName: voice_no]];
    3611             :                                         }
    3612             :                                 }
    3613             :                         }
    3614             :                         speechGenderSelectKeyPressed = YES;
    3615             :                 }
    3616             :                 else
    3617             :                         speechGenderSelectKeyPressed = NO;
    3618             :         }
    3619             : #endif
    3620             : #endif
    3621             :         
    3622             :         if ((guiSelectedRow == GUI_ROW(GAME,MUSIC))&&(([self checkKeyPress:n_key_gui_arrow_right])||([self checkKeyPress:n_key_gui_arrow_left])))
    3623             :         {
    3624             :                 if (!musicModeKeyPressed)
    3625             :                 {
    3626             :                         OOMusicController       *musicController = [OOMusicController sharedController];
    3627             :                         int                                     initialMode = [musicController mode];
    3628             :                         int                                     mode = initialMode;
    3629             :                         
    3630             :                         if ([self checkKeyPress:n_key_gui_arrow_right])  mode++;
    3631             :                         if ([self checkKeyPress:n_key_gui_arrow_left])  mode--;
    3632             :                         
    3633             :                         [musicController setMode:MAX(mode, 0)];
    3634             :                         
    3635             :                         if ((int)[musicController mode] != initialMode)
    3636             :                         {
    3637             :                                 [self playChangedOption];
    3638             :                                 NSString *musicMode = [UNIVERSE descriptionForArrayKey:@"music-mode" index:[[OOMusicController sharedController] mode]];
    3639             :                                 NSString *message = OOExpandKey(@"gameoptions-music-mode", musicMode);
    3640             :                                 [gui setText:message forRow:GUI_ROW(GAME,MUSIC) align:GUI_ALIGN_CENTER];
    3641             :                         }
    3642             :                 }
    3643             :                 musicModeKeyPressed = YES;
    3644             :         }
    3645             :         else  musicModeKeyPressed = NO;
    3646             :         
    3647             :         if ((guiSelectedRow == GUI_ROW(GAME,AUTOSAVE))&&(([self checkKeyPress:n_key_gui_arrow_right])||([self checkKeyPress:n_key_gui_arrow_left])))
    3648             :         {
    3649             :                 if ([self checkKeyPress:n_key_gui_arrow_right] != [UNIVERSE autoSave])
    3650             :                         [self playChangedOption];
    3651             :                 [UNIVERSE setAutoSave:[self checkKeyPress:n_key_gui_arrow_right]];
    3652             :                 if ([UNIVERSE autoSave])
    3653             :                 {
    3654             :                         // if just enabled, we want to autosave immediately
    3655             :                         [UNIVERSE setAutoSaveNow:YES];
    3656             :                         [gui setText:DESC(@"gameoptions-autosave-yes")        forRow:GUI_ROW(GAME,AUTOSAVE)  align:GUI_ALIGN_CENTER];
    3657             :                 }
    3658             :                 else
    3659             :                 {
    3660             :                         [UNIVERSE setAutoSaveNow:NO];
    3661             :                         [gui setText:DESC(@"gameoptions-autosave-no") forRow:GUI_ROW(GAME,AUTOSAVE)  align:GUI_ALIGN_CENTER];
    3662             :                 }
    3663             :         }
    3664             : 
    3665             :         if ((guiSelectedRow == GUI_ROW(GAME,VOLUME))
    3666             :                 &&(([self checkKeyPress:n_key_gui_arrow_right])||([self checkKeyPress:n_key_gui_arrow_left]))
    3667             :                 &&[OOSound respondsToSelector:@selector(masterVolume)])
    3668             :         {
    3669             :                 if ((!volumeControlPressed)||(script_time > timeLastKeyPress + KEY_REPEAT_INTERVAL))
    3670             :                 {
    3671             :                         BOOL rightKeyDown = [self checkKeyPress:n_key_gui_arrow_right];
    3672             :                         BOOL leftKeyDown = [self checkKeyPress:n_key_gui_arrow_left];
    3673             :                         double volume = 100.0 * [OOSound masterVolume];
    3674             :                         int vol = (volume / 5.0 + 0.5);
    3675             :                         if (rightKeyDown) vol++;
    3676             :                         if (leftKeyDown) vol--;
    3677             :                         vol = (int)OOClampInteger(vol, 0, 20);
    3678             :                         [OOSound setMasterVolume: 0.05 * vol];
    3679             :                         [self playChangedOption];
    3680             : #if OOLITE_ESPEAK
    3681             :                         espeak_SetParameter(espeakVOLUME, vol * 5, 0);
    3682             : #endif
    3683             :                         if (vol > 0)
    3684             :                         {
    3685             :                                 NSString* soundVolumeWordDesc = DESC(@"gameoptions-sound-volume");
    3686             :                                 NSString* v1_string = @"|||||||||||||||||||||||||";
    3687             :                                 NSString* v0_string = @".........................";
    3688             :                                 v1_string = [v1_string substringToIndex:vol];
    3689             :                                 v0_string = [v0_string substringToIndex:20 - vol];
    3690             :                                 [gui setText:[NSString stringWithFormat:@"%@%@%@ ", soundVolumeWordDesc, v1_string, v0_string]
    3691             :                                           forRow:GUI_ROW(GAME,VOLUME)
    3692             :                                            align:GUI_ALIGN_CENTER];
    3693             :                         }
    3694             :                         else
    3695             :                                 [gui setText:DESC(@"gameoptions-sound-volume-mute")   forRow:GUI_ROW(GAME,VOLUME)  align:GUI_ALIGN_CENTER];
    3696             :                         timeLastKeyPress = script_time;
    3697             :                 }
    3698             :                 volumeControlPressed = YES;
    3699             :         }
    3700             :         else
    3701             :                 volumeControlPressed = NO;
    3702             :                 
    3703             : #if OOLITE_SDL
    3704             :         if ((guiSelectedRow == GUI_ROW(GAME,GAMMA))
    3705             :                 &&(([self checkKeyPress:n_key_gui_arrow_right])||([self checkKeyPress:n_key_gui_arrow_left])))
    3706             :         {
    3707             :                 if (!gammaControlPressed)
    3708             :                 {
    3709             :                         BOOL rightKeyDown = [self checkKeyPress:n_key_gui_arrow_right];
    3710             :                         BOOL leftKeyDown = [self checkKeyPress:n_key_gui_arrow_left];
    3711             :                         float gamma = [gameView gammaValue];
    3712             :                         gamma += (((rightKeyDown && (gamma < 4.0f)) ? 0.2f : 0.0f) - ((leftKeyDown && (gamma > 0.2f)) ? 0.2f : 0.0f));
    3713             :                         if (gamma > 3.95f) gamma = 4.0f;
    3714             :                         if (gamma < 0.25f) gamma = 0.2f;
    3715             :                         [gameView setGammaValue:gamma];
    3716             :                         int gamma5 = gamma * 5; // avoid rounding errors
    3717             :                         NSString* gammaWordDesc = DESC(@"gameoptions-gamma-value");
    3718             :                         NSString* v1_string = @"|||||||||||||||||||||||||";
    3719             :                         NSString* v0_string = @".........................";
    3720             :                         v1_string = [v1_string substringToIndex:gamma5];
    3721             :                         v0_string = [v0_string substringToIndex:20 - gamma5];
    3722             :                         [gui setText:[NSString stringWithFormat:@"%@%@%@ (%.1f) ", gammaWordDesc, v1_string, v0_string, gamma]        forRow:GUI_ROW(GAME,GAMMA)  align:GUI_ALIGN_CENTER];
    3723             :                 }
    3724             :                 gammaControlPressed = YES;
    3725             :         }
    3726             :         else
    3727             :                 gammaControlPressed = NO;
    3728             : #endif
    3729             : 
    3730             : 
    3731             :         if ((guiSelectedRow == GUI_ROW(GAME,FOV))
    3732             :                 &&(([self checkKeyPress:n_key_gui_arrow_right])||([self checkKeyPress:n_key_gui_arrow_left])))
    3733             :         {
    3734             :                 if (!fovControlPressed ||(script_time > timeLastKeyPress + KEY_REPEAT_INTERVAL))
    3735             :                 {
    3736             :                         BOOL rightKeyDown = [self checkKeyPress:n_key_gui_arrow_right];
    3737             :                         BOOL leftKeyDown = [self checkKeyPress:n_key_gui_arrow_left];
    3738             :                         float fov = [gameView fov:NO];
    3739             :                         float fovStep = (MAX_FOV_DEG - MIN_FOV_DEG) / 20.0f;
    3740             :                         fov += (((rightKeyDown && (fov < MAX_FOV_DEG)) ?
    3741             :                                                 fovStep : 0.0f) - ((leftKeyDown && (fov > MIN_FOV_DEG)) ? fovStep : 0.0f));
    3742             :                         if (fov > MAX_FOV_DEG) fov = MAX_FOV_DEG;
    3743             :                         if (fov < MIN_FOV_DEG) fov = MIN_FOV_DEG;
    3744             :                         [gameView setFov:fov fromFraction:NO];
    3745             :                         fieldOfView = [gameView fov:YES];
    3746             :                         int fovTicks = (int)((fov - MIN_FOV_DEG) / fovStep);
    3747             :                         NSString* fovWordDesc = DESC(@"gameoptions-fov-value");
    3748             :                         NSString* v1_string = @"|||||||||||||||||||||||||";
    3749             :                         NSString* v0_string = @".........................";
    3750             :                         v1_string = [v1_string substringToIndex:fovTicks];
    3751             :                         v0_string = [v0_string substringToIndex:20 - fovTicks];
    3752             :                         [gui setText:[NSString stringWithFormat:@"%@%@%@ (%d%c) ", fovWordDesc, v1_string, v0_string, (int)fov, 176 /*176 is the degrees symbol ASCII code*/] forRow:GUI_ROW(GAME,FOV)  align:GUI_ALIGN_CENTER];
    3753             :                         [[NSUserDefaults standardUserDefaults] setFloat:[gameView fov:NO] forKey:@"fov-value"];
    3754             :                         timeLastKeyPress = script_time;
    3755             :                 }
    3756             :                 fovControlPressed = YES;
    3757             :         }
    3758             :         else
    3759             :                 fovControlPressed = NO;
    3760             : 
    3761             :         
    3762             :         // color blind mode
    3763             :         if ((guiSelectedRow == GUI_ROW(GAME,COLORBLINDMODE))&&(([self checkKeyPress:n_key_gui_arrow_right])||([self checkKeyPress:n_key_gui_arrow_left])))
    3764             :         {
    3765             :                 if (!colorblindModeControlPressed)
    3766             :                 {
    3767             :                         int colorblindMode = [UNIVERSE colorblindMode];
    3768             :                         if ([self checkKeyPress:n_key_gui_arrow_right])
    3769             :                         {
    3770             :                                 [UNIVERSE setCurrentPostFX:[UNIVERSE nextColorblindMode:colorblindMode]];
    3771             :                         }
    3772             :                         else
    3773             :                         {
    3774             :                                 [UNIVERSE setCurrentPostFX:[UNIVERSE prevColorblindMode:colorblindMode]];
    3775             :                         }
    3776             :                         colorblindMode = [UNIVERSE colorblindMode]; // get the updated value
    3777             :                         NSString *colorblindModeDesc = [[[UNIVERSE descriptions] oo_arrayForKey: @"colorblind_mode"] oo_stringAtIndex:[UNIVERSE useShaders] ? colorblindMode : 0];
    3778             :                         NSString *colorblindModeMsg = OOExpandKey(@"gameoptions-colorblind-mode", colorblindModeDesc);
    3779             :                         [gui setText:colorblindModeMsg forRow:GUI_ROW(GAME,COLORBLINDMODE) align:GUI_ALIGN_CENTER];
    3780             :                 }
    3781             :                 colorblindModeControlPressed = YES;
    3782             :         }
    3783             :         else
    3784             :                 colorblindModeControlPressed = NO;
    3785             :         
    3786             :         
    3787             :         if (![gameView hdrOutput])
    3788             :         {
    3789             :                 if ((guiSelectedRow == GUI_ROW(GAME,WIREFRAMEGRAPHICS))&&(([self checkKeyPress:n_key_gui_arrow_right])||([self checkKeyPress:n_key_gui_arrow_left])))
    3790             :                 {
    3791             :                         if ([self checkKeyPress:n_key_gui_arrow_right] != [UNIVERSE wireframeGraphics])
    3792             :                                 [self playChangedOption];
    3793             :                         [UNIVERSE setWireframeGraphics:[self checkKeyPress:n_key_gui_arrow_right]];
    3794             :                         if ([UNIVERSE wireframeGraphics])
    3795             :                                 [gui setText:DESC(@"gameoptions-wireframe-graphics-yes")  forRow:GUI_ROW(GAME,WIREFRAMEGRAPHICS)  align:GUI_ALIGN_CENTER];
    3796             :                         else
    3797             :                                 [gui setText:DESC(@"gameoptions-wireframe-graphics-no")  forRow:GUI_ROW(GAME,WIREFRAMEGRAPHICS)  align:GUI_ALIGN_CENTER];
    3798             :                 }
    3799             :         }
    3800             : #if OOLITE_WINDOWS
    3801             :         else
    3802             :         {
    3803             :                 if ((guiSelectedRow == GUI_ROW(GAME,HDRPAPERWHITE))
    3804             :                 &&(([self checkKeyPress:n_key_gui_arrow_right])||([self checkKeyPress:n_key_gui_arrow_left])))
    3805             :                 {
    3806             :                         if (!hdrPaperWhiteControlPressed)
    3807             :                         {
    3808             :                                 BOOL rightKeyDown = [self checkKeyPress:n_key_gui_arrow_right];
    3809             :                                 BOOL leftKeyDown = [self checkKeyPress:n_key_gui_arrow_left];
    3810             :                                 float paperWhite = [gameView hdrPaperWhiteBrightness];
    3811             :                                 paperWhite += (((rightKeyDown && (paperWhite < MAX_HDR_PAPERWHITE)) ? 10.0f : 0.0f) - ((leftKeyDown && (paperWhite > MIN_HDR_PAPERWHITE)) ? 10.0f : 0.0f));
    3812             :                                 if (paperWhite > MAX_HDR_PAPERWHITE) paperWhite = MAX_HDR_PAPERWHITE;
    3813             :                                 if (paperWhite < MIN_HDR_PAPERWHITE) paperWhite = MIN_HDR_PAPERWHITE;
    3814             :                                 [gameView setHDRPaperWhiteBrightness:paperWhite];
    3815             :                                 int paperWhiteNorm = (int)((paperWhite - MIN_HDR_PAPERWHITE) * 20 / (MAX_HDR_PAPERWHITE - MIN_HDR_PAPERWHITE));
    3816             :                                 NSString* paperWhiteWordDesc = DESC(@"gameoptions-hdr-paperwhite");
    3817             :                                 NSString* v1_string = @"|||||||||||||||||||||||||";
    3818             :                                 NSString* v0_string = @".........................";
    3819             :                                 v1_string = [v1_string substringToIndex:paperWhiteNorm];
    3820             :                                 v0_string = [v0_string substringToIndex:20 - paperWhiteNorm];
    3821             :                                 [gui setText:[NSString stringWithFormat:@"%@%@%@ (%d) ", paperWhiteWordDesc, v1_string, v0_string, (int)paperWhite]   forRow:GUI_ROW(GAME,HDRPAPERWHITE)  align:GUI_ALIGN_CENTER];
    3822             :                         }
    3823             :                         hdrPaperWhiteControlPressed = YES;
    3824             :                 }
    3825             :                 else
    3826             :                         hdrPaperWhiteControlPressed = NO;
    3827             :         }
    3828             : #endif
    3829             :         
    3830             : #if !NEW_PLANETS
    3831             :         if ((guiSelectedRow == GUI_ROW(GAME,PROCEDURALLYTEXTUREDPLANETS))&&(([self checkKeyPress:n_key_gui_arrow_right])||([self checkKeyPress:n_key_gui_arrow_left])))
    3832             :         {
    3833             :                 if ([self checkKeyPress:n_key_gui_arrow_right] != [UNIVERSE doProcedurallyTexturedPlanets])
    3834             :                 {
    3835             :                         [UNIVERSE setDoProcedurallyTexturedPlanets:[self checkKeyPress:n_key_gui_arrow_right]];
    3836             :                         [self playChangedOption];
    3837             :                         if ([UNIVERSE planet])
    3838             :                         {
    3839             :                                 [UNIVERSE setUpPlanet];
    3840             :                         }
    3841             :                 }
    3842             :                 if ([UNIVERSE doProcedurallyTexturedPlanets])
    3843             :                         [gui setText:DESC(@"gameoptions-procedurally-textured-planets-yes")  forRow:GUI_ROW(GAME,PROCEDURALLYTEXTUREDPLANETS)  align:GUI_ALIGN_CENTER];
    3844             :                 else
    3845             :                         [gui setText:DESC(@"gameoptions-procedurally-textured-planets-no")  forRow:GUI_ROW(GAME,PROCEDURALLYTEXTUREDPLANETS)  align:GUI_ALIGN_CENTER];
    3846             :         }
    3847             : #endif
    3848             :         
    3849             :         if (guiSelectedRow == GUI_ROW(GAME,SHADEREFFECTS) && ([self checkKeyPress:n_key_gui_arrow_right] || [self checkKeyPress:n_key_gui_arrow_left]))
    3850             :         {
    3851             :                 if (!shaderSelectKeyPressed || (script_time > timeLastKeyPress + KEY_REPEAT_INTERVAL))
    3852             :                 {
    3853             :                         int direction = ([self checkKeyPress:n_key_gui_arrow_right]) ? 1 : -1;
    3854             : 
    3855             :                         /* (Getafix - 2015/05/07)
    3856             :                         Fix bug coincidentally resulting in Graphics Detail value cycling 
    3857             :                         when left arrow is pressed.
    3858             :                         
    3859             :                         OOGraphicsDetail is an enum type and as such it will never go 
    3860             :                         negative. The following code adjusts "direction" to avoid illegal
    3861             :                         detailLevel values.
    3862             :                         
    3863             :                         Perhaps a more elegant solution could be set in place, restructuring 
    3864             :                         in Universe.m the logic behing setDetailLevelDirectly and 
    3865             :                         setDetailLevel, not forgetting to consider Graphic Detail assigned 
    3866             :                         from various sources (i.e. menu, user prefs file, javascript, etc.). 
    3867             :                         This is postponed in order not to risk the recently announced 
    3868             :                         plans for v1.82 release.
    3869             :                         
    3870             :                         Generally we should decide whether the menu values should cycle or 
    3871             :                         not and apply it for all menu entries.
    3872             :                         */ 
    3873             :                         if ((([UNIVERSE detailLevel] == DETAIL_LEVEL_MINIMUM) && (direction == -1)) || 
    3874             :                                         (([UNIVERSE detailLevel] == DETAIL_LEVEL_MAXIMUM) && (direction == 1)))
    3875             :                                 direction = 0;
    3876             :                         
    3877             :                         OOGraphicsDetail detailLevel = [UNIVERSE detailLevel] + direction;
    3878             :                         [UNIVERSE setDetailLevel:detailLevel];
    3879             :                         detailLevel = [UNIVERSE detailLevel];
    3880             : 
    3881             :                         NSString *shaderEffectsOptionsString = OOExpand(@"gameoptions-detaillevel-[detailLevel]", detailLevel);
    3882             :                         [gui setText:OOExpandKey(shaderEffectsOptionsString) forRow:GUI_ROW(GAME,SHADEREFFECTS) align:GUI_ALIGN_CENTER];
    3883             :                         [gui setKey:GUI_KEY_OK forRow:GUI_ROW(GAME,SHADEREFFECTS)];
    3884             : 
    3885             :                         timeLastKeyPress = script_time;
    3886             :                         
    3887             :                         // changing detail level may result in changes to other settings too
    3888             :                         // (e.g. colorblind mode status), so refresh the page
    3889             :                         [self setGuiToGameOptionsScreen];
    3890             :                         [gui setSelectedRow:GUI_ROW(GAME,SHADEREFFECTS)];
    3891             :                 }
    3892             :                 shaderSelectKeyPressed = YES;
    3893             :         }
    3894             :         else shaderSelectKeyPressed = NO;
    3895             :         
    3896             : #if OOLITE_SDL
    3897             :         if ((guiSelectedRow == GUI_ROW(GAME,DISPLAYSTYLE)) && selectKeyPress)
    3898             :         {
    3899             :                 [gameView toggleScreenMode];
    3900             :                 // redraw GUI
    3901             :                 [self setGuiToGameOptionsScreen];
    3902             :         }
    3903             : #endif
    3904             : 
    3905             :         if ((guiSelectedRow == GUI_ROW(GAME,DOCKINGCLEARANCE))&&(([self checkKeyPress:n_key_gui_arrow_right])||([self checkKeyPress:n_key_gui_arrow_left])))
    3906             :         {
    3907             :                 if ([self checkKeyPress:n_key_gui_arrow_right] != [UNIVERSE dockingClearanceProtocolActive])
    3908             :                         [self playChangedOption];
    3909             :                 [UNIVERSE setDockingClearanceProtocolActive:[self checkKeyPress:n_key_gui_arrow_right]];
    3910             :                 if ([UNIVERSE dockingClearanceProtocolActive])
    3911             :                         [gui setText:DESC(@"gameoptions-docking-clearance-yes")  forRow:GUI_ROW(GAME,DOCKINGCLEARANCE)  align:GUI_ALIGN_CENTER];
    3912             :                 else
    3913             :                         [gui setText:DESC(@"gameoptions-docking-clearance-no")  forRow:GUI_ROW(GAME,DOCKINGCLEARANCE)  align:GUI_ALIGN_CENTER];
    3914             :         }
    3915             :         
    3916             :         if ((guiSelectedRow == GUI_ROW(GAME,BACK)) && selectKeyPress)
    3917             :         {
    3918             :                 [gameView clearKeys];
    3919             :                 [self setGuiToLoadSaveScreen];
    3920             :         }
    3921             : }
    3922             : 
    3923             : 
    3924             : - (void) handleKeyMapperScreenKeys
    3925             : {
    3926             :         MyOpenGLView    *gameView = [UNIVERSE gameView];
    3927             :         GuiDisplayGen   *gui = [UNIVERSE gui];
    3928             : 
    3929             :         [self keyMapperInputHandler: gui view: gameView];
    3930             :         leftRightKeyPressed = [self checkKeyPress:n_key_gui_arrow_right] || [self checkKeyPress:n_key_gui_arrow_left] || [self checkKeyPress:n_key_gui_page_up] || [self checkKeyPress:n_key_gui_page_down];
    3931             :         if (leftRightKeyPressed)
    3932             :         {
    3933             :                 NSString *key = [gui keyForRow: [gui selectedRow]];
    3934             :                 if ([self checkKeyPress:n_key_gui_arrow_right] || [self checkKeyPress:n_key_gui_page_down])
    3935             :                 {
    3936             :                         key = [gui keyForRow:GUI_ROW_KC_FUNCEND];
    3937             :                 }
    3938             :                 if ([self checkKeyPress:n_key_gui_arrow_left] || [self checkKeyPress:n_key_gui_page_up])
    3939             :                 {
    3940             :                         key = [gui keyForRow:GUI_ROW_KC_FUNCSTART];
    3941             :                 }
    3942             :                 int from_function = 0;
    3943             :                 NSArray *keyComponents = [key componentsSeparatedByString:@":"];
    3944             :                 if ([keyComponents count] > 1)
    3945             :                 {
    3946             :                         from_function = [keyComponents oo_intAtIndex:1];
    3947             :                         if (from_function < 0)  from_function = 0;
    3948             :                         
    3949             :                         [self setGuiToKeyMapperScreen:from_function resetCurrentRow: YES];
    3950             :                         if ([[UNIVERSE gui] selectedRow] < GUI_ROW_KC_FUNCSTART)
    3951             :                         {
    3952             :                                 [[UNIVERSE gui] setSelectedRow: GUI_ROW_KC_FUNCSTART];
    3953             :                         }
    3954             :                         if (from_function == 0)
    3955             :                         {
    3956             :                                 [[UNIVERSE gui] setSelectedRow: GUI_ROW_KC_FUNCSTART + MAX_ROWS_KC_FUNCTIONS - 1];
    3957             :                         }
    3958             :                 }
    3959             :         }
    3960             : }
    3961             : 
    3962             : 
    3963             : - (void) handleKeyboardLayoutKeys
    3964             : {
    3965             :         MyOpenGLView    *gameView = [UNIVERSE gameView];
    3966             :         GuiDisplayGen   *gui = [UNIVERSE gui];
    3967             :         
    3968             :         [self handleKeyboardLayoutEntryKeys: gui view: gameView];
    3969             :         leftRightKeyPressed = [self checkKeyPress:n_key_gui_arrow_right] || [self checkKeyPress:n_key_gui_arrow_left] || [self checkKeyPress:n_key_gui_page_up] || [self checkKeyPress:n_key_gui_page_down];
    3970             :         if (leftRightKeyPressed)
    3971             :         {
    3972             :                 NSString *key = [gui keyForRow: [gui selectedRow]];
    3973             :                 if ([self checkKeyPress:n_key_gui_arrow_right] || [self checkKeyPress:n_key_gui_page_down])
    3974             :                 {
    3975             :                         key = [gui keyForRow:GUI_ROW_KC_FUNCEND];
    3976             :                 }
    3977             :                 if ([self checkKeyPress:n_key_gui_arrow_left] || [self checkKeyPress:n_key_gui_page_up])
    3978             :                 {
    3979             :                         key = [gui keyForRow:GUI_ROW_KC_FUNCSTART];
    3980             :                 }
    3981             :                 int from_function = 0;
    3982             :                 NSArray *keyComponents = [key componentsSeparatedByString:@":"];
    3983             :                 if ([keyComponents count] > 1)
    3984             :                 {
    3985             :                         from_function = [keyComponents oo_intAtIndex:1];
    3986             :                         if (from_function < 0)  from_function = 0;
    3987             :                         
    3988             :                         [self setGuiToKeyboardLayoutScreen:from_function resetCurrentRow:YES];
    3989             :                         if ([[UNIVERSE gui] selectedRow] < GUI_ROW_KC_FUNCSTART)
    3990             :                         {
    3991             :                                 [[UNIVERSE gui] setSelectedRow: GUI_ROW_KC_FUNCSTART];
    3992             :                         }
    3993             :                         if (from_function == 0)
    3994             :                         {
    3995             :                                 [[UNIVERSE gui] setSelectedRow: GUI_ROW_KC_FUNCSTART + MAX_ROWS_KC_FUNCTIONS - 1];
    3996             :                         }
    3997             :                 }
    3998             :         }
    3999             : }
    4000             : 
    4001             : 
    4002             : - (void) handleStickMapperScreenKeys
    4003             : {
    4004             :         MyOpenGLView    *gameView = [UNIVERSE gameView];
    4005             :         GuiDisplayGen   *gui = [UNIVERSE gui];
    4006             :         
    4007             :         [self stickMapperInputHandler: gui view: gameView];
    4008             :         leftRightKeyPressed = [self checkKeyPress:n_key_gui_arrow_right] || [self checkKeyPress:n_key_gui_arrow_left] || [self checkKeyPress:n_key_gui_page_up] || [self checkKeyPress:n_key_gui_page_down];
    4009             :         if (leftRightKeyPressed)
    4010             :         {
    4011             :                 NSString *key = [gui keyForRow: [gui selectedRow]];
    4012             :                 if ([self checkKeyPress:n_key_gui_arrow_right] || [self checkKeyPress:n_key_gui_page_down])
    4013             :                 {
    4014             :                         key = [gui keyForRow:GUI_ROW_FUNCEND];
    4015             :                 }
    4016             :                 if ([self checkKeyPress:n_key_gui_arrow_left] || [self checkKeyPress:n_key_gui_page_up])
    4017             :                 {
    4018             :                         key = [gui keyForRow:GUI_ROW_FUNCSTART];
    4019             :                 }
    4020             :                 int from_function = 0;
    4021             :                 NSArray *keyComponents = [key componentsSeparatedByString:@":"];
    4022             :                 if ([keyComponents count] > 1)
    4023             :                 {
    4024             :                         from_function = [keyComponents oo_intAtIndex:1];
    4025             :                         if (from_function < 0)  from_function = 0;
    4026             :                         
    4027             :                         [self setGuiToStickMapperScreen:from_function resetCurrentRow: YES];
    4028             :                         if ([[UNIVERSE gui] selectedRow] < GUI_ROW_FUNCSTART)
    4029             :                         {
    4030             :                                 [[UNIVERSE gui] setSelectedRow: GUI_ROW_FUNCSTART];
    4031             :                         }
    4032             :                         if (from_function == 0)
    4033             :                         {
    4034             :                                 [[UNIVERSE gui] setSelectedRow: GUI_ROW_FUNCSTART + MAX_ROWS_FUNCTIONS - 1];
    4035             :                         }
    4036             :                 }
    4037             :         }
    4038             :         if([gameView isDown:' '])  [self setGuiToGameOptionsScreen];
    4039             : }
    4040             : 
    4041             : 
    4042             : - (void) pollCustomViewControls
    4043             : {
    4044             :         static Quaternion viewQuaternion;
    4045             :         static Vector viewOffset;
    4046             :         static Vector rotationCenter;
    4047             :         static Vector up;
    4048             :         static Vector right;
    4049             :         static BOOL mouse_clicked = NO;
    4050             :         static NSPoint mouse_clicked_position;
    4051             :         static BOOL shift_down;
    4052             :         static BOOL caps_on = NO;
    4053             :         static NSTimeInterval last_time = 0.0;
    4054             :         MyOpenGLView *gameView = [UNIVERSE gameView];
    4055             :         const BOOL *joyButtonState = [[OOJoystickManager sharedStickHandler] getAllButtonStates];
    4056             : 
    4057             :         if ([self checkKeyPress:n_key_custom_view] || joyButtonState[BUTTON_EXTVIEWCYCLE])
    4058             :         {
    4059             :                 if (!customView_pressed && [_customViews count] != 0 && gui_screen != GUI_SCREEN_LONG_RANGE_CHART && ![gameView allowingStringInput])
    4060             :                 {
    4061             :                         if ([UNIVERSE viewDirection] == VIEW_CUSTOM)    // already in custom view mode
    4062             :                         {
    4063             :                                 // rotate the custom views
    4064             :                                 _customViewIndex = (_customViewIndex + 1) % [_customViews count];
    4065             :                         }
    4066             :         
    4067             :                         [self setCustomViewDataFromDictionary:[_customViews oo_dictionaryAtIndex:_customViewIndex] withScaling:YES];
    4068             :         
    4069             :                         [self switchToThisView:VIEW_CUSTOM andProcessWeaponFacing:NO]; // weapon facing must not change, we just want an external view
    4070             :                 }
    4071             :                 customView_pressed = YES;
    4072             :         }
    4073             :         else
    4074             :                 customView_pressed = NO;
    4075             :         NSTimeInterval this_time = [NSDate timeIntervalSinceReferenceDate];
    4076             :         if ([UNIVERSE viewDirection] > VIEW_STARBOARD && [gameView isCapsLockOn])
    4077             :         {
    4078             :                 BOOL ctrl_down = [gameView isCtrlDown];
    4079             :                 float customViewZoomSpeed = ctrl_down ? CUSTOM_VIEW_ZOOM_SPEED * CUSTOM_VIEW_SPEED_REDUCTION_FACTOR: CUSTOM_VIEW_ZOOM_SPEED;
    4080             :                 float customViewRotateSpeed = ctrl_down ? CUSTOM_VIEW_ROTATE_SPEED * CUSTOM_VIEW_SPEED_REDUCTION_FACTOR: CUSTOM_VIEW_ROTATE_SPEED;
    4081             :                 
    4082             :                 if (!caps_on)  caps_on = YES;
    4083             :                 
    4084             :                 OOTimeDelta delta_t = this_time - last_time;
    4085             :                 if (([self checkKeyPress:n_key_custom_view_zoom_out ignore_ctrl:YES] && ![self checkKeyPress:n_key_custom_view_zoom_in ignore_ctrl:YES]) || [gameView mouseWheelState] == gvMouseWheelDown)
    4086             :                 {
    4087             :                         [self customViewZoomOut: pow(customViewZoomSpeed, delta_t)];
    4088             :                 }
    4089             :                 if (([self checkKeyPress:n_key_custom_view_zoom_in ignore_ctrl:YES] && ![self checkKeyPress:n_key_custom_view_zoom_out ignore_ctrl:YES]) || [gameView mouseWheelState] == gvMouseWheelUp)
    4090             :                 {
    4091             :                         [self customViewZoomIn: pow(customViewZoomSpeed, delta_t)];
    4092             :                 }
    4093             :                 if ([self checkKeyPress:n_key_custom_view_roll_left ignore_ctrl:YES] && ![self checkKeyPress:n_key_custom_view_roll_right ignore_ctrl:YES])
    4094             :                 {
    4095             :                         [self customViewRollLeft:customViewRotateSpeed * delta_t];
    4096             :                 }
    4097             :                 if ([self checkKeyPress:n_key_custom_view_pan_left ignore_ctrl:YES] && ![self checkKeyPress:n_key_custom_view_pan_right ignore_ctrl:YES])
    4098             :                 {
    4099             :                         [self customViewPanLeft:customViewRotateSpeed * delta_t];
    4100             :                 }
    4101             :                 if ([self checkKeyPress:n_key_custom_view_roll_right ignore_ctrl:YES] && ![self checkKeyPress:n_key_custom_view_roll_left ignore_ctrl:YES])
    4102             :                 {
    4103             :                         [self customViewRollRight:customViewRotateSpeed * delta_t];
    4104             :                 }
    4105             :                 if ([self checkKeyPress:n_key_custom_view_pan_right ignore_ctrl:YES] && ![self checkKeyPress:n_key_custom_view_pan_left ignore_ctrl:YES])
    4106             :                 {
    4107             :                         [self customViewPanRight:customViewRotateSpeed * delta_t];
    4108             :                 }
    4109             :                 if ([self checkKeyPress:n_key_custom_view_rotate_up ignore_ctrl:YES] && ![self checkKeyPress:n_key_custom_view_rotate_down ignore_ctrl:YES])
    4110             :                 {
    4111             :                         [self customViewRotateUp:customViewRotateSpeed * delta_t];
    4112             :                 }
    4113             :                 if ([self checkKeyPress:n_key_custom_view_pan_down ignore_ctrl:YES] && ![self checkKeyPress:n_key_custom_view_pan_up ignore_ctrl:YES])
    4114             :                 {
    4115             :                         [self customViewPanDown:customViewRotateSpeed * delta_t];
    4116             :                 }
    4117             :                 if ([self checkKeyPress:n_key_custom_view_rotate_down ignore_ctrl:YES] && ![self checkKeyPress:n_key_custom_view_rotate_up ignore_ctrl:YES])
    4118             :                 {
    4119             :                         [self customViewRotateDown:customViewRotateSpeed * delta_t];
    4120             :                 }
    4121             :                 if ([self checkKeyPress:n_key_custom_view_pan_up ignore_ctrl:YES] && ![self checkKeyPress:n_key_custom_view_pan_down ignore_ctrl:YES])
    4122             :                 {
    4123             :                         [self customViewPanUp:customViewRotateSpeed * delta_t];
    4124             :                 }
    4125             :                 if ([self checkKeyPress:n_key_custom_view_rotate_left ignore_ctrl:YES] && ![self checkKeyPress:n_key_custom_view_rotate_right ignore_ctrl:YES])
    4126             :                 {
    4127             :                         [self customViewRotateLeft:customViewRotateSpeed * delta_t];
    4128             :                 }
    4129             :                 if ([self checkKeyPress:n_key_custom_view_rotate_right ignore_ctrl:YES] && ![self checkKeyPress:n_key_custom_view_rotate_left ignore_ctrl:YES])
    4130             :                 {
    4131             :                         [self customViewRotateRight:customViewRotateSpeed * delta_t];
    4132             :                 }
    4133             :                 if ([gameView isDown:gvMouseLeftButton])
    4134             :                 {
    4135             :                         if(!mouse_clicked || shift_down != [gameView isShiftDown])
    4136             :                         {
    4137             :                                 mouse_clicked = YES;
    4138             :                                 viewQuaternion = [PLAYER customViewQuaternion];
    4139             :                                 viewOffset = [PLAYER customViewOffset];
    4140             :                                 rotationCenter = [PLAYER customViewRotationCenter];
    4141             :                                 up = [PLAYER customViewUpVector];
    4142             :                                 right = [PLAYER customViewRightVector];
    4143             :                                 mouse_clicked_position = [gameView virtualJoystickPosition];
    4144             :                                 shift_down = [gameView isShiftDown];
    4145             :                         }
    4146             :                         NSPoint mouse_position = [gameView virtualJoystickPosition];
    4147             :                         Vector axis = vector_add(vector_multiply_scalar(up, mouse_position.x - mouse_clicked_position.x),
    4148             :                                 vector_multiply_scalar(right, mouse_position.y - mouse_clicked_position.y));
    4149             :                         float angle = magnitude(axis);
    4150             :                         axis = vector_normal(axis);
    4151             :                         Quaternion newViewQuaternion = viewQuaternion;
    4152             :                         if ([gameView isShiftDown])
    4153             :                         {
    4154             :                                 quaternion_rotate_about_axis(&newViewQuaternion, axis, angle);
    4155             :                                 [PLAYER setCustomViewQuaternion: newViewQuaternion];
    4156             :                                 [PLAYER setCustomViewRotationCenter: vector_subtract(viewOffset,
    4157             :                                         vector_multiply_scalar([PLAYER customViewForwardVector],
    4158             :                                                 dot_product([PLAYER customViewForwardVector], viewOffset)))];
    4159             :                         }
    4160             :                         else
    4161             :                         {
    4162             :                                 quaternion_rotate_about_axis(&newViewQuaternion, axis, -angle);
    4163             :                                 OOScalar m = magnitude(vector_subtract(viewOffset, rotationCenter));
    4164             :                                 [PLAYER setCustomViewQuaternion: newViewQuaternion];
    4165             :                                 Vector offset = vector_flip([PLAYER customViewForwardVector]);
    4166             :                                 scale_vector(&offset, m / magnitude(offset));
    4167             :                                 [PLAYER setCustomViewOffset:vector_add(offset, rotationCenter)];
    4168             :                         }
    4169             :                 }
    4170             :                 else
    4171             :                 {
    4172             :                         mouse_clicked = NO;
    4173             :                 }
    4174             :         }
    4175             :         else
    4176             :         {
    4177             :                 mouse_clicked = NO;
    4178             :                 if (caps_on)
    4179             :                 {
    4180             :                         caps_on = NO;
    4181             :                         if ([self isMouseControlOn])  [gameView resetMouse];
    4182             :                 }
    4183             :         }
    4184             :         last_time = this_time;
    4185             : }
    4186             : 
    4187             : 
    4188             : - (void) pollViewControls
    4189             : {
    4190             :         if(!pollControls)
    4191             :                 return;
    4192             :         
    4193             :         MyOpenGLView    *gameView = [UNIVERSE gameView];
    4194             :         OOJoystickManager *stickHandler = [OOJoystickManager sharedStickHandler];
    4195             :         
    4196             :         NSPoint                 virtualView = NSZeroPoint;
    4197             :         double                  view_threshold = 0.5;
    4198             :         
    4199             :         if ([stickHandler joystickCount])
    4200             :         {
    4201             :                 virtualView = [stickHandler viewAxis];
    4202             :                 if (virtualView.y == STICK_AXISUNASSIGNED)
    4203             :                         virtualView.y = 0.0;
    4204             :                 if (virtualView.x == STICK_AXISUNASSIGNED)
    4205             :                         virtualView.x = 0.0;
    4206             :                 if (fabs(virtualView.y) >= fabs(virtualView.x))
    4207             :                         virtualView.x = 0.0; // forward/aft takes precedence
    4208             :                 else
    4209             :                         virtualView.y = 0.0;
    4210             :         }
    4211             :         
    4212             :         const BOOL *joyButtonState = [stickHandler getAllButtonStates];
    4213             :         
    4214             :         //  view keys
    4215             :         if (([self checkKeyPress:n_key_view_forward]) || (virtualView.y < -view_threshold)||joyButtonState[BUTTON_VIEWFORWARD] || ((([self checkKeyPress:n_key_hyperspace] && gui_screen != GUI_SCREEN_LONG_RANGE_CHART) || joyButtonState[BUTTON_HYPERDRIVE]) && [UNIVERSE displayGUI]))
    4216             :         {
    4217             :                 [self switchToThisView:VIEW_FORWARD];
    4218             :         }
    4219             :         if (([self checkKeyPress:n_key_view_aft])||(virtualView.y > view_threshold)||joyButtonState[BUTTON_VIEWAFT])
    4220             :         {
    4221             :                 [self switchToThisView:VIEW_AFT];
    4222             :         }
    4223             :         if (([self checkKeyPress:n_key_view_port])||(virtualView.x < -view_threshold)||joyButtonState[BUTTON_VIEWPORT])
    4224             :         {
    4225             :                 [self switchToThisView:VIEW_PORT];
    4226             :         }
    4227             :         if (([self checkKeyPress:n_key_view_starboard])||(virtualView.x > view_threshold)||joyButtonState[BUTTON_VIEWSTARBOARD])
    4228             :         {
    4229             :                 [self switchToThisView:VIEW_STARBOARD];
    4230             :         }
    4231             :         
    4232             :         [self pollCustomViewControls];
    4233             :         
    4234             :         // Zoom scanner 'z'
    4235             :         if (([self checkKeyPress:n_key_scanner_zoom] && ([gameView allowingStringInput] == gvStringInputNo)) || joyButtonState[BUTTON_SCANNERZOOM]) // look for the 'z' key
    4236             :         {
    4237             :                 if (!scanner_zoom_rate)
    4238             :                 {
    4239             :                         if ([hud scannerZoom] < 5.0)
    4240             :                         {
    4241             :                                 if (([hud scannerZoom] > 1.0)||(!zoom_pressed))
    4242             :                                         scanner_zoom_rate = SCANNER_ZOOM_RATE_UP;
    4243             :                         }
    4244             :                         else
    4245             :                         {
    4246             :                                 if (!zoom_pressed)      // must release and re-press zoom to zoom back down..
    4247             :                                         scanner_zoom_rate = SCANNER_ZOOM_RATE_DOWN;
    4248             :                         }
    4249             :                 }
    4250             :                 zoom_pressed = YES;
    4251             :         }
    4252             :         else
    4253             :                 zoom_pressed = NO;
    4254             :         
    4255             :         // Unzoom scanner 'Z'
    4256             :         if (([self checkKeyPress:n_key_scanner_unzoom] && ([gameView allowingStringInput] == gvStringInputNo)) || joyButtonState[BUTTON_SCANNERUNZOOM]) // look for the 'Z' key
    4257             :         {
    4258             :                 if ((!scanner_zoom_rate)&&([hud scannerZoom] > 1.0))
    4259             :                         scanner_zoom_rate = SCANNER_ZOOM_RATE_DOWN;
    4260             :         }
    4261             :         
    4262             :         if (EXPECT([[self hud] isCompassActive]))       // only switch compass modes if there is a compass
    4263             :         {
    4264             :                 // Compass mode '|'
    4265             :                 if ([self checkKeyPress:n_key_prev_compass_mode] || joyButtonState[BUTTON_COMPASSMODE_PREV]) // look for the '|' key
    4266             :                 {
    4267             :                         if ((!prev_compass_mode_pressed)&&(compassMode != COMPASS_MODE_BASIC))
    4268             :                                 [self setPrevCompassMode];
    4269             :                         prev_compass_mode_pressed = YES;
    4270             :                 }
    4271             :                 else
    4272             :                 {
    4273             :                         prev_compass_mode_pressed = NO;
    4274             :                 }
    4275             :                 // Compass mode '\'
    4276             :                 if ([self checkKeyPress:n_key_next_compass_mode] || joyButtonState[BUTTON_COMPASSMODE]) // look for the '\' key
    4277             :                 {
    4278             :                         if ((!next_compass_mode_pressed)&&(compassMode != COMPASS_MODE_BASIC))
    4279             :                                 [self setNextCompassMode];
    4280             :                         next_compass_mode_pressed = YES;
    4281             :                 }
    4282             :                 else
    4283             :                 {
    4284             :                         next_compass_mode_pressed = NO;
    4285             :                 }
    4286             :         }
    4287             :         
    4288             :         // ';' // Cycle active MFD
    4289             :         if ([self checkKeyPress:n_key_cycle_next_mfd] || [self checkKeyPress:n_key_cycle_previous_mfd] || joyButtonState[BUTTON_MFDCYCLENEXT] || joyButtonState[BUTTON_MFDCYCLEPREV])
    4290             :         {
    4291             :                 if (!cycleMFD_pressed)
    4292             :                 {
    4293             :                         //if (![gameView isCtrlDown]) 
    4294             :                         if (![self checkKeyPress:n_key_cycle_previous_mfd] || joyButtonState[BUTTON_MFDCYCLEPREV]) 
    4295             :                         {
    4296             :                                 [self cycleNextMultiFunctionDisplay:activeMFD];
    4297             :                         }
    4298             :                         else
    4299             :                         {
    4300             :                                 [self cyclePreviousMultiFunctionDisplay:activeMFD];
    4301             :                         }
    4302             :                 }
    4303             :                 cycleMFD_pressed = YES;
    4304             :         }
    4305             :         else
    4306             :         {
    4307             :                 cycleMFD_pressed = NO;
    4308             :         }
    4309             : 
    4310             :         //  ':' // Select next MFD
    4311             :         if ([self checkKeyPress:n_key_switch_next_mfd] || [self checkKeyPress:n_key_switch_previous_mfd] || joyButtonState[BUTTON_MFDSELECTNEXT] || joyButtonState[BUTTON_MFDSELECTPREV])
    4312             :         {
    4313             :                 if ([[self hud] mfdCount] > 1)
    4314             :                 {
    4315             :                         if (!switchMFD_pressed)
    4316             :                         {
    4317             :                                 //if (![gameView isCtrlDown])
    4318             :                                 if (![self checkKeyPress:n_key_switch_previous_mfd] || joyButtonState[BUTTON_MFDSELECTPREV])
    4319             :                                 {
    4320             :                                         [self selectNextMultiFunctionDisplay];
    4321             :                                 }
    4322             :                                 else
    4323             :                                 {
    4324             :                                         [self selectPreviousMultiFunctionDisplay];
    4325             :                                 }
    4326             :                         }
    4327             :                 }
    4328             :                 switchMFD_pressed = YES;
    4329             :         }
    4330             :         else
    4331             :         {
    4332             :                 switchMFD_pressed = NO;
    4333             :         }
    4334             :                                 
    4335             : 
    4336             :         //  show comms log '`'
    4337             :         if ([self checkKeyPress:n_key_comms_log])
    4338             :         {
    4339             :                 [UNIVERSE showCommsLog: 1.5];
    4340             :                 [hud refreshLastTransmitter];
    4341             :         }
    4342             : }
    4343             : 
    4344             : 
    4345             : - (void) pollFlightArrowKeyControls:(double)delta_t
    4346             : {
    4347             :         MyOpenGLView            *gameView = [UNIVERSE gameView];
    4348             :         OOJoystickManager       *stickHandler = [OOJoystickManager sharedStickHandler];
    4349             :         NSUInteger                      numSticks = [stickHandler joystickCount];
    4350             :         NSPoint                         virtualStick = NSZeroPoint;
    4351             :         double                          reqYaw = 0.0;
    4352             :         
    4353             :         /*      DJS: Handle inputs on the joy roll/pitch axis.
    4354             :          Mouse control on takes precedence over joysticks.
    4355             :          We have to assume the player has a reason for switching mouse
    4356             :          control on if they have a joystick - let them do it. */
    4357             :         if (mouse_control_on)
    4358             :         {
    4359             :                 virtualStick=[gameView virtualJoystickPosition];
    4360             :                 double sensitivity = 2.0;
    4361             :                 virtualStick.x *= sensitivity;
    4362             :                 virtualStick.y *= sensitivity;
    4363             :                 reqYaw = virtualStick.x;
    4364             :         }
    4365             :         else if (numSticks > 0)
    4366             :         {
    4367             :                 virtualStick = [stickHandler rollPitchAxis];
    4368             :                 // handle roll separately (fix for BUG #17490)
    4369             :                 if(virtualStick.x == STICK_AXISUNASSIGNED)
    4370             :                 {
    4371             :                         // Not assigned - set to zero.
    4372             :                         virtualStick.x=0;
    4373             :                 }
    4374             :                 else if(virtualStick.x != 0)
    4375             :                 {
    4376             :                         // cancel keyboard override, stick has been waggled
    4377             :                         keyboardRollOverride=NO;
    4378             :                 }
    4379             :                 // handle pitch separately (fix for BUG #17490)
    4380             :                 if(virtualStick.y == STICK_AXISUNASSIGNED)
    4381             :                 {
    4382             :                         // Not assigned - set to zero.
    4383             :                         virtualStick.y=0;
    4384             :                 }
    4385             :                 else if(virtualStick.y != 0)
    4386             :                 {
    4387             :                         // cancel keyboard override, stick has been waggled
    4388             :                         keyboardPitchOverride=NO;
    4389             :                 }
    4390             :                 // handle yaw separately from pitch/roll
    4391             :                 reqYaw = [stickHandler getAxisState: AXIS_YAW];
    4392             :                 if(reqYaw == STICK_AXISUNASSIGNED)
    4393             :                 {
    4394             :                         // Not assigned or deadzoned - set to zero.
    4395             :                         reqYaw=0;
    4396             :                 }
    4397             :                 else if(reqYaw != 0)
    4398             :                 {
    4399             :                         // cancel keyboard override, stick has been waggled
    4400             :                         keyboardYawOverride=NO;
    4401             :                 }
    4402             :         }
    4403             :         
    4404             :         double roll_dampner = ROLL_DAMPING_FACTOR * delta_t;
    4405             :         double pitch_dampner = PITCH_DAMPING_FACTOR * delta_t;
    4406             :         double yaw_dampner = YAW_DAMPING_FACTOR * delta_t;
    4407             :         BOOL capsLockCustomView = [UNIVERSE viewDirection] == VIEW_CUSTOM && [gameView isCapsLockOn];
    4408             :         
    4409             :         BOOL    isCtrlDown = [gameView isCtrlDown];
    4410             :         
    4411             :         double  flightArrowKeyPrecisionFactor = [[NSUserDefaults standardUserDefaults] oo_doubleForKey:@"flight-arrow-key-precision-factor" defaultValue:0.5];
    4412             :         if (flightArrowKeyPrecisionFactor < 0.05)  flightArrowKeyPrecisionFactor = 0.05;
    4413             :         if (flightArrowKeyPrecisionFactor > 1.0)  flightArrowKeyPrecisionFactor = 1.0; 
    4414             :         
    4415             :         rolling = NO;
    4416             :         // if we have yaw on the mouse x-axis, then allow using the keyboard roll keys
    4417             :         if (!mouse_control_on || (mouse_control_on && mouse_x_axis_map_to_yaw))
    4418             :         {
    4419             :                 if ([self checkNavKeyPress:n_key_roll_left] && [self checkNavKeyPress:n_key_roll_right])
    4420             :                 {
    4421             :                         keyboardRollOverride = YES;
    4422             :                         flightRoll = 0.0;
    4423             :                 }
    4424             :                 else if ([self checkNavKeyPress:n_key_roll_left] && !capsLockCustomView)
    4425             :                 {
    4426             :                         keyboardRollOverride=YES;
    4427             :                         if (flightRoll > 0.0)  flightRoll = 0.0;
    4428             :                         [self decrease_flight_roll:isCtrlDown ? flightArrowKeyPrecisionFactor*roll_dampner*roll_delta : delta_t*roll_delta];
    4429             :                         rolling = YES;
    4430             :                 }
    4431             :                 else if ([self checkNavKeyPress:n_key_roll_right] && !capsLockCustomView)
    4432             :                 {
    4433             :                         keyboardRollOverride=YES;
    4434             :                         if (flightRoll < 0.0)  flightRoll = 0.0;
    4435             :                         [self increase_flight_roll:isCtrlDown ? flightArrowKeyPrecisionFactor*roll_dampner*roll_delta : delta_t*roll_delta];
    4436             :                         rolling = YES;
    4437             :                 }
    4438             :         }
    4439             :         if(((mouse_control_on && !mouse_x_axis_map_to_yaw) || numSticks) && !keyboardRollOverride && !capsLockCustomView)
    4440             :         {
    4441             :                 stick_roll = max_flight_roll * virtualStick.x;
    4442             :                 if (flightRoll < stick_roll)
    4443             :                 {
    4444             :                         [self increase_flight_roll:delta_t*roll_delta];
    4445             :                         if (flightRoll > stick_roll)
    4446             :                                 flightRoll = stick_roll;
    4447             :                 }
    4448             :                 if (flightRoll > stick_roll)
    4449             :                 {
    4450             :                         [self decrease_flight_roll:delta_t*roll_delta];
    4451             :                         if (flightRoll < stick_roll)
    4452             :                                 flightRoll = stick_roll;
    4453             :                 }
    4454             :                 rolling = (fabs(virtualStick.x) > 0.0);
    4455             :         }
    4456             :         if (!rolling)
    4457             :         {
    4458             :                 if (flightRoll > 0.0)
    4459             :                 {
    4460             :                         if (flightRoll > roll_dampner)       [self decrease_flight_roll:roll_dampner];
    4461             :                         else    flightRoll = 0.0;
    4462             :                 }
    4463             :                 if (flightRoll < 0.0)
    4464             :                 {
    4465             :                         if (flightRoll < -roll_dampner)   [self increase_flight_roll:roll_dampner];
    4466             :                         else    flightRoll = 0.0;
    4467             :                 }
    4468             :         }
    4469             :         
    4470             :         pitching = NO;
    4471             :         // we don't care about pitch keyboard overrides when mouse control is on, only when using joystick
    4472             :         if (!mouse_control_on)
    4473             :         {
    4474             :                 if ([self checkNavKeyPress:n_key_pitch_back] && [self checkNavKeyPress:n_key_pitch_forward])
    4475             :                 {
    4476             :                         keyboardPitchOverride=YES;
    4477             :                         flightPitch = 0.0;
    4478             :                 }
    4479             :                 else if ([self checkNavKeyPress:n_key_pitch_back] && !capsLockCustomView)
    4480             :                 {
    4481             :                         keyboardPitchOverride=YES;
    4482             :                         if (flightPitch < 0.0)  flightPitch = 0.0;
    4483             :                         [self increase_flight_pitch:isCtrlDown ? flightArrowKeyPrecisionFactor*pitch_dampner*pitch_delta : delta_t*pitch_delta];
    4484             :                         pitching = YES;
    4485             :                 }
    4486             :                 else if ([self checkNavKeyPress:n_key_pitch_forward] && !capsLockCustomView)
    4487             :                 {
    4488             :                         keyboardPitchOverride=YES;
    4489             :                         if (flightPitch > 0.0)  flightPitch = 0.0;
    4490             :                         [self decrease_flight_pitch:isCtrlDown ? flightArrowKeyPrecisionFactor*pitch_dampner*pitch_delta : delta_t*pitch_delta];
    4491             :                         pitching = YES;
    4492             :                 }
    4493             :         }
    4494             :         if((mouse_control_on || (numSticks && !keyboardPitchOverride)) && !capsLockCustomView)
    4495             :         {
    4496             :                 stick_pitch = max_flight_pitch * virtualStick.y;
    4497             :                 if (flightPitch < stick_pitch)
    4498             :                 {
    4499             :                         [self increase_flight_pitch:delta_t*pitch_delta];
    4500             :                         if (flightPitch > stick_pitch)
    4501             :                                 flightPitch = stick_pitch;
    4502             :                 }
    4503             :                 if (flightPitch > stick_pitch)
    4504             :                 {
    4505             :                         [self decrease_flight_pitch:delta_t*pitch_delta];
    4506             :                         if (flightPitch < stick_pitch)
    4507             :                                 flightPitch = stick_pitch;
    4508             :                 }
    4509             :                 pitching = (fabs(virtualStick.y) > 0.0);
    4510             :         }
    4511             :         if (!pitching)
    4512             :         {
    4513             :                 if (flightPitch > 0.0)
    4514             :                 {
    4515             :                         if (flightPitch > pitch_dampner)     [self decrease_flight_pitch:pitch_dampner];
    4516             :                         else    flightPitch = 0.0;
    4517             :                 }
    4518             :                 if (flightPitch < 0.0)
    4519             :                 {
    4520             :                         if (flightPitch < -pitch_dampner)    [self increase_flight_pitch:pitch_dampner];
    4521             :                         else    flightPitch = 0.0;
    4522             :                 }
    4523             :         }
    4524             :         
    4525             :         yawing = NO;
    4526             :         // if we have roll on the mouse x-axis, then allow using the keyboard yaw keys
    4527             :         if (!mouse_control_on || (mouse_control_on && !mouse_x_axis_map_to_yaw))
    4528             :         {
    4529             :                 if ([self checkNavKeyPress:n_key_yaw_left] && [self checkNavKeyPress:n_key_yaw_right])
    4530             :                 {
    4531             :                         keyboardYawOverride=YES;
    4532             :                         flightYaw = 0.0;
    4533             :                 }
    4534             :                 else if ([self checkNavKeyPress:n_key_yaw_left] && !capsLockCustomView)
    4535             :                 {
    4536             :                         keyboardYawOverride=YES;
    4537             :                         if (flightYaw < 0.0)  flightYaw = 0.0;
    4538             :                         [self increase_flight_yaw:isCtrlDown ? flightArrowKeyPrecisionFactor*yaw_dampner*yaw_delta : delta_t*yaw_delta];
    4539             :                         yawing = YES;
    4540             :                 }
    4541             :                 else if ([self checkNavKeyPress:n_key_yaw_right] && !capsLockCustomView)
    4542             :                 {
    4543             :                         keyboardYawOverride=YES;
    4544             :                         if (flightYaw > 0.0)  flightYaw = 0.0;
    4545             :                         [self decrease_flight_yaw:isCtrlDown ? flightArrowKeyPrecisionFactor*yaw_dampner*yaw_delta : delta_t*yaw_delta];
    4546             :                         yawing = YES;
    4547             :                 }
    4548             :         }
    4549             :         if(((mouse_control_on && mouse_x_axis_map_to_yaw) || numSticks) && !keyboardYawOverride && !capsLockCustomView)
    4550             :         {
    4551             :                 // I think yaw is handled backwards in the code,
    4552             :                 // which is why the negative sign is here.
    4553             :                 stick_yaw = max_flight_yaw * (-reqYaw);
    4554             :                 if (flightYaw < stick_yaw)
    4555             :                 {
    4556             :                         [self increase_flight_yaw:delta_t*yaw_delta];
    4557             :                         if (flightYaw > stick_yaw)
    4558             :                                 flightYaw = stick_yaw;
    4559             :                 }
    4560             :                 if (flightYaw > stick_yaw)
    4561             :                 {
    4562             :                         [self decrease_flight_yaw:delta_t*yaw_delta];
    4563             :                         if (flightYaw < stick_yaw)
    4564             :                                 flightYaw = stick_yaw;
    4565             :                 }
    4566             :                 yawing = (fabs(reqYaw) > 0.0);
    4567             :         }
    4568             :         if (!yawing)
    4569             :         {
    4570             :                 if (flightYaw > 0.0)
    4571             :                 {
    4572             :                         if (flightYaw > yaw_dampner) [self decrease_flight_yaw:yaw_dampner];
    4573             :                         else    flightYaw = 0.0;
    4574             :                 }
    4575             :                 if (flightYaw < 0.0)
    4576             :                 {
    4577             :                         if (flightYaw < -yaw_dampner)   [self increase_flight_yaw:yaw_dampner];
    4578             :                         else    flightYaw = 0.0;
    4579             :                 }
    4580             :         }
    4581             : 
    4582             : }
    4583             : 
    4584             : 
    4585             : - (void) pollGuiScreenControls
    4586             : {
    4587             :         [self pollGuiScreenControlsWithFKeyAlias:YES];
    4588             : }
    4589             : 
    4590             : 
    4591             : - (void) pollGuiScreenControlsWithFKeyAlias:(BOOL)fKeyAlias
    4592             : {
    4593             :         if(!pollControls && fKeyAlias)  // Still OK to run, if we don't use number keys.
    4594             :                 return;
    4595             :         
    4596             :         GuiDisplayGen   *gui = [UNIVERSE gui];
    4597             :         MyOpenGLView    *gameView = [UNIVERSE gameView];
    4598             :         BOOL                    docked_okay = ([self status] == STATUS_DOCKED);
    4599             :         
    4600             :         //  text displays
    4601             :         if ([self checkKeyPress:n_key_gui_screen_status fKey_only:!fKeyAlias])
    4602             :         {
    4603             :                 if (!switching_status_screens)
    4604             :                 {
    4605             :                         switching_status_screens = YES;
    4606             :                         if (gui_screen == GUI_SCREEN_STATUS)
    4607             :                         {
    4608             :                                 [self noteGUIWillChangeTo:GUI_SCREEN_MANIFEST];
    4609             :                                 [self setGuiToManifestScreen];
    4610             :                         }
    4611             :                         else
    4612             :                                 [self setGuiToStatusScreen];
    4613             :                         [self checkScript];
    4614             :                 }
    4615             :         }
    4616             :         else
    4617             :         {
    4618             :                 switching_status_screens = NO;
    4619             :         }
    4620             :         
    4621             :         if ([self checkKeyPress:n_key_gui_chart_screens fKey_only:!fKeyAlias])
    4622             :         {
    4623             :                 mouse_left_down = NO;
    4624             :                 [gameView clearMouse];
    4625             :                 if  (!switching_chart_screens)
    4626             :                 {
    4627             :                         switching_chart_screens = YES;
    4628             :                         // handles http://aegidian.org/bb/viewtopic.php?p=233189#p233189
    4629             :                         if (EXPECT_NOT([self status] == STATUS_WITCHSPACE_COUNTDOWN && gui_screen == GUI_SCREEN_SHORT_RANGE_CHART)) 
    4630             :                         {
    4631             :                                 // don't switch to LRC if countdown in progress
    4632             :                                 switching_chart_screens = NO;
    4633             :                         }
    4634             :                         else if (gui_screen == GUI_SCREEN_SHORT_RANGE_CHART || (gui_screen == GUI_SCREEN_SYSTEM_DATA && showingLongRangeChart))
    4635             :                         {
    4636             :                                 if (target_chart_zoom != CHART_MAX_ZOOM)
    4637             :                                 {
    4638             :                                         saved_chart_zoom = target_chart_zoom;
    4639             :                                 }
    4640             :                                 target_chart_zoom = CHART_MAX_ZOOM;
    4641             :                                 [self noteGUIWillChangeTo:GUI_SCREEN_LONG_RANGE_CHART];
    4642             :                                 [self setGuiToLongRangeChartScreen];
    4643             :                         }
    4644             :                         else
    4645             :                         {
    4646             :                                 if (target_chart_zoom == CHART_MAX_ZOOM)
    4647             :                                 {
    4648             :                                         target_chart_zoom = saved_chart_zoom;
    4649             :                                 }
    4650             :                                 //target_chart_centre = cursor_coordinates = [[UNIVERSE systemManager] getCoordinatesForSystem:target_system_id inGalaxy:galaxy_number];
    4651             :                                 [self noteGUIWillChangeTo:GUI_SCREEN_SHORT_RANGE_CHART];
    4652             :                                 [self setGuiToShortRangeChartScreen];
    4653             :                         }
    4654             :                 }
    4655             :         }
    4656             :         else
    4657             :         {
    4658             :                 switching_chart_screens = NO;
    4659             :         }
    4660             :         
    4661             :         if ([self checkKeyPress:n_key_gui_system_data fKey_only:!fKeyAlias])
    4662             :         {
    4663             :                 if (gui_screen != GUI_SCREEN_SYSTEM_DATA)
    4664             :                 {
    4665             :                         showingLongRangeChart = (gui_screen == GUI_SCREEN_LONG_RANGE_CHART);
    4666             :                         [self noteGUIWillChangeTo:GUI_SCREEN_SYSTEM_DATA];
    4667             :                         [self setGuiToSystemDataScreen];
    4668             :                 }
    4669             :         }
    4670             : 
    4671             :         if ([self checkKeyPress:n_key_gui_market fKey_only:!fKeyAlias])
    4672             :         {
    4673             :                 if (gui_screen != GUI_SCREEN_MARKET)
    4674             :                 {
    4675             :                         [gameView clearKeys];
    4676             :                         [self noteGUIWillChangeTo:GUI_SCREEN_MARKET];
    4677             :                         [self setGuiToMarketScreen];
    4678             :                 }
    4679             :                 else
    4680             :                 {
    4681             :                         [gameView clearKeys];
    4682             :                         [self noteGUIWillChangeTo:GUI_SCREEN_MARKETINFO];
    4683             :                         [self setGuiToMarketInfoScreen];
    4684             :                 }
    4685             :         }
    4686             :         
    4687             :         
    4688             :         if (docked_okay)
    4689             :         {       
    4690             :                 if (([self checkKeyPress:n_key_gui_screen_options fKey_only:!fKeyAlias]) && (gui_screen != GUI_SCREEN_OPTIONS))
    4691             :                 {
    4692             :                         [gameView clearKeys];
    4693             :                         [self setGuiToLoadSaveScreen];
    4694             :                 }
    4695             :                 
    4696             :                 if ([self checkKeyPress:n_key_gui_screen_equipship fKey_only:!fKeyAlias])
    4697             :                 {
    4698             :                         if (!switching_equipship_screens)
    4699             :                         {
    4700             :                                 if ([self dockedStation] == nil)  [self setDockedAtMainStation];
    4701             :                                 OOGUIScreenID oldScreen = gui_screen;
    4702             :                                 
    4703             :                                 if ((gui_screen == GUI_SCREEN_EQUIP_SHIP) && [[self dockedStation] hasShipyard])
    4704             :                                 {
    4705             :                                         [gameView clearKeys];
    4706             :                                         [self noteGUIWillChangeTo:GUI_SCREEN_SHIPYARD];
    4707             :                                         [self setGuiToShipyardScreen:0];
    4708             :                                         [gui setSelectedRow:GUI_ROW_SHIPYARD_START];
    4709             :                                         [self showShipyardInfoForSelection];
    4710             :                                 }
    4711             :                                 else
    4712             :                                 {
    4713             :                                         [gameView clearKeys];
    4714             :                                         [self noteGUIWillChangeTo:GUI_SCREEN_EQUIP_SHIP];
    4715             :                                         [self setGuiToEquipShipScreen:0];
    4716             :                                         [gui setSelectedRow:GUI_ROW_EQUIPMENT_START];
    4717             :                                 }
    4718             :                                 
    4719             :                                 [self noteGUIDidChangeFrom:oldScreen to:gui_screen]; 
    4720             :                         }
    4721             :                         switching_equipship_screens = YES;
    4722             :                 }
    4723             :                 else
    4724             :                 {
    4725             :                         switching_equipship_screens = NO;
    4726             :                 }
    4727             :                 
    4728             :                 if ([self checkKeyPress:n_key_gui_screen_interfaces fKey_only:!fKeyAlias])
    4729             :                 {
    4730             :                         [self setGuiToInterfacesScreen:0];
    4731             :                         [gui setSelectedRow:GUI_ROW_INTERFACES_START];
    4732             :                 }
    4733             : 
    4734             :         }
    4735             : }
    4736             : 
    4737             : 
    4738             : - (void) pollGameOverControls:(double)delta_t
    4739             : {
    4740             :         MyOpenGLView  *gameView = [UNIVERSE gameView];
    4741             :         if ([gameView isDown:32])   // look for the spacebar
    4742             :         {
    4743             :                 if (!spacePressed)
    4744             :                 {
    4745             :                         [UNIVERSE displayMessage:@"" forCount:1.0];
    4746             :                         shot_time = INITIAL_SHOT_TIME;  // forces immediate restart
    4747             :                 }
    4748             :                 spacePressed = YES;
    4749             :         }
    4750             :         else
    4751             :                 spacePressed = NO;
    4752             : }
    4753             : 
    4754             : 
    4755           0 : static BOOL toggling_music;
    4756           0 : static BOOL playing_music;
    4757           0 : static BOOL autopilot_pause;
    4758             : 
    4759             : - (void) pollAutopilotControls:(double)delta_t
    4760             : {
    4761             :         // don't do anything if we're configuring the keyboard
    4762             :         if (gui_screen == GUI_SCREEN_KEYBOARD_ENTRY || gui_screen == GUI_SCREEN_KEYBOARD_CONFIG || gui_screen == GUI_SCREEN_KEYBOARD_LAYOUT || gui_screen == GUI_SCREEN_KEYBOARD || gui_screen == GUI_SCREEN_KEYBOARD_CONFIRMCLEAR) return;
    4763             : 
    4764             :         const BOOL *joyButtonState = [[OOJoystickManager sharedStickHandler] getAllButtonStates];
    4765             : 
    4766             :         // controls polled while the autopilot is active
    4767             :         if (![[UNIVERSE gameController] isGamePaused])
    4768             :         {
    4769             :                 //  view keys
    4770             :                 [self pollViewControls];
    4771             :                 
    4772             :                 //  text displays
    4773             :                 [self pollGuiScreenControls];
    4774             :                 
    4775             :                 if ([UNIVERSE displayGUI])
    4776             :                         [self pollGuiArrowKeyControls:delta_t];
    4777             :                 
    4778             :                 if ([self checkKeyPress:n_key_autopilot] || joyButtonState[BUTTON_DOCKCPU]
    4779             :                         || [self checkKeyPress:n_key_autodock] || joyButtonState[BUTTON_DOCKCPUFAST])   // look for the 'c' and 'C' key
    4780             :                 {
    4781             :                         if ([self hasDockingComputer] && !autopilot_key_pressed && !fast_autopilot_key_pressed)
    4782             :                         {
    4783             :                                 [self disengageAutopilot];
    4784             :                                 [UNIVERSE addMessage:DESC(@"autopilot-off") forCount:4.5];
    4785             :                         }
    4786             :                         autopilot_key_pressed = YES;
    4787             :                         if ([self checkKeyPress:n_key_autodock] || joyButtonState[BUTTON_DOCKCPUFAST])
    4788             :                         {
    4789             :                                 fast_autopilot_key_pressed = YES;
    4790             :                         }
    4791             :                 }
    4792             :                 else
    4793             :                 {
    4794             :                         autopilot_key_pressed = NO;
    4795             :                         fast_autopilot_key_pressed = NO;
    4796             :                 }
    4797             :                 
    4798             :                 if (([self checkKeyPress:n_key_docking_music] || joyButtonState[BUTTON_DOCKINGMUSIC]))   // look for the 's' key
    4799             :                 {
    4800             :                         if (!toggling_music)
    4801             :                         {
    4802             :                                 [[OOMusicController sharedController] toggleDockingMusic];
    4803             :                         }
    4804             :                         toggling_music = YES;
    4805             :                 }
    4806             :                 else
    4807             :                 {
    4808             :                         toggling_music = NO;
    4809             :                 }
    4810             :                 // look for the pause game, 'p' key
    4811             :                 if (([self checkKeyPress:n_key_pausebutton] || joyButtonState[BUTTON_PAUSE]) && gui_screen != GUI_SCREEN_SHORT_RANGE_CHART && gui_screen != GUI_SCREEN_MISSION && gui_screen != GUI_SCREEN_KEYBOARD_ENTRY)
    4812             :                 {
    4813             :                         if (!autopilot_pause)
    4814             :                         {
    4815             :                                 playing_music = [[OOMusicController sharedController] isPlaying];
    4816             :                                 if (playing_music)  [[OOMusicController sharedController] toggleDockingMusic];
    4817             :                                 // normal flight controls can handle the rest.
    4818             :                                 pause_pressed = NO;     // pause button flag must be NO for pollflightControls to react!
    4819             :                                 [self pollFlightControls:delta_t];
    4820             :                         }
    4821             :                         autopilot_pause = YES;
    4822             :                 }
    4823             :                 else
    4824             :                 {
    4825             :                         autopilot_pause = NO;
    4826             :                 }
    4827             :         }
    4828             :         else
    4829             :         {
    4830             :                 // paused
    4831             :                 if ([self checkKeyPress:n_key_pausebutton] || joyButtonState[BUTTON_PAUSE])
    4832             :                 {
    4833             :                         if (!autopilot_pause)
    4834             :                         {
    4835             :                                 if (playing_music)  [[OOMusicController sharedController] toggleDockingMusic];
    4836             :                         }
    4837             :                         autopilot_pause = YES;
    4838             :                 }
    4839             :                 else
    4840             :                 {
    4841             :                         autopilot_pause = NO;
    4842             :                 }
    4843             :                 // let the normal flight controls handle paused commands.
    4844             :                 [self pollFlightControls:delta_t];
    4845             :         }
    4846             : }
    4847             : 
    4848             : 
    4849             : - (void) pollDockedControls:(double)delta_t
    4850             : {
    4851             :         MyOpenGLView                    *gameView = [UNIVERSE gameView];
    4852             :         GameController                  *gameController = [UNIVERSE gameController];
    4853             :         const BOOL *joyButtonState = [[OOJoystickManager sharedStickHandler] getAllButtonStates];
    4854             :         NSString                                *exceptionContext = @"setup";
    4855             :         
    4856             :         @try
    4857             :         {
    4858             :                 // Pause game, 'p' key
    4859             :                 exceptionContext = @"pause key";
    4860             :                 if (([self checkKeyPress:n_key_pausebutton] || joyButtonState[BUTTON_PAUSE]) && (gui_screen != GUI_SCREEN_LONG_RANGE_CHART &&
    4861             :                                 gui_screen != GUI_SCREEN_MISSION && gui_screen != GUI_SCREEN_REPORT &&
    4862             :                                 gui_screen != GUI_SCREEN_SAVE && gui_screen != GUI_SCREEN_KEYBOARD_ENTRY) )
    4863             :                 {
    4864             :                         if (!pause_pressed)
    4865             :                         {
    4866             :                                 if ([gameController isGamePaused])
    4867             :                                 {
    4868             :                                         script_time = saved_script_time;
    4869             :                                         [gameView allowStringInput:NO];
    4870             :                                         if ([UNIVERSE pauseMessageVisible])
    4871             :                                         {
    4872             :                                                 [UNIVERSE clearPreviousMessage];        // remove the 'paused' message.
    4873             :                                         }
    4874             :                                         [[UNIVERSE gui] setForegroundTextureKey:@"docked_overlay"];
    4875             :                                         [gameController setGamePaused:NO];
    4876             :                                 }
    4877             :                                 else
    4878             :                                 {
    4879             :                                         saved_script_time = script_time;
    4880             :                                         [[UNIVERSE messageGUI] clear];
    4881             :                                         
    4882             :                                         [UNIVERSE pauseGame];   // 'paused' handler
    4883             :                                 }
    4884             :                         }
    4885             :                         pause_pressed = YES;
    4886             :                 }
    4887             :                 else
    4888             :                 {
    4889             :                         pause_pressed = NO;
    4890             :                 }
    4891             :                 
    4892             :                 if ([gameController isGamePaused]) return;
    4893             :                 
    4894             :                 if(pollControls)
    4895             :                 {
    4896             :                         exceptionContext = @"undock";
    4897             :                         if ([self checkKeyPress:n_key_launch_ship])
    4898             :                         {
    4899             :                                 if (EXPECT((gui_screen != GUI_SCREEN_MISSION || _missionAllowInterrupt) && gui_screen != GUI_SCREEN_KEYBOARD_ENTRY))
    4900             :                                 {
    4901             :                                         [self handleUndockControl];
    4902             :                                 }
    4903             :                         }
    4904             :                 }
    4905             :                 
    4906             :                 //  text displays
    4907             :                 // mission screens
    4908             :                 exceptionContext = @"GUI keys";
    4909             :                 if (gui_screen == GUI_SCREEN_MISSION || gui_screen == GUI_SCREEN_KEYBOARD_ENTRY)
    4910             :                 {
    4911             :                         [self pollDemoControls: delta_t];       // don't switch away from mission screens
    4912             :                 }
    4913             :                 else
    4914             :                 {
    4915             :                         if (gui_screen != GUI_SCREEN_REPORT)[self pollGuiScreenControls];       // don't switch away from report screens
    4916             :                 }
    4917             :                 
    4918             :                 [self pollGuiArrowKeyControls:delta_t];
    4919             :         }
    4920             :         @catch (NSException *exception)
    4921             :         {
    4922             :                 OOLog(kOOLogException, @"***** Exception in pollDockedControls [%@]: %@ : %@", exceptionContext, [exception name], [exception reason]);
    4923             :         }
    4924             : }
    4925             : 
    4926             : 
    4927             : - (void) handleUndockControl
    4928             : {
    4929             :         // FIXME: should this not be in leaveDock:? (Note: leaveDock: is also called from script method launchFromStation and -[StationEntity becomeExplosion]) -- Ahruman 20080308
    4930             :         [UNIVERSE setUpUniverseFromStation]; // player pre-launch
    4931             :         if ([self dockedStation] == nil)  [self setDockedAtMainStation];
    4932             :         
    4933             :         StationEntity *dockedStation = [self dockedStation];
    4934             :         if (dockedStation == [UNIVERSE station] && [UNIVERSE autoSaveNow] && !([[UNIVERSE sun] goneNova] || [[UNIVERSE sun] willGoNova]))
    4935             :         {
    4936             :                 [self autosavePlayer];
    4937             :         }
    4938             :         [self launchFromStation];
    4939             : }
    4940             : 
    4941             : 
    4942             : - (void) pollDemoControls:(double)delta_t
    4943             : {
    4944             :         MyOpenGLView    *gameView = [UNIVERSE gameView];
    4945             :         GuiDisplayGen   *gui = [UNIVERSE gui];
    4946             :         NSUInteger end_row = 21;
    4947             :         OOOXZManager *oxzmanager = [OOOXZManager sharedManager];
    4948             : 
    4949             :         switch (gui_screen)
    4950             :         {
    4951             :                 case GUI_SCREEN_INTRO1:
    4952             :                         [self handleGUIUpDownArrowKeys];
    4953             : 
    4954             :                         int row_zero = 21;
    4955             :                         if (!selectPressed)
    4956             :                         {
    4957             :                                 if (!disc_operation_in_progress)
    4958             :                                 {
    4959             :                                         if (([gameView isDown:gvMouseDoubleClick] || [self checkKeyPress:n_key_gui_select]) && [gui selectedRow] == 2+row_zero)
    4960             :                                         {
    4961             :                                                 disc_operation_in_progress = YES;
    4962             :                                                 [UNIVERSE removeDemoShips];
    4963             :                                                 [gui clearBackground];
    4964             :                                                 if (![self loadPlayer])
    4965             :                                                 {
    4966             :                                                         [self setGuiToIntroFirstGo:YES];
    4967             :                                                 }
    4968             :                                                 break;
    4969             :                                         }
    4970             :                                 }
    4971             :                                 if (([gameView isDown:gvMouseDoubleClick] || [self checkKeyPress:n_key_gui_select]) && [gui selectedRow] == 1+row_zero)
    4972             :                                 {
    4973             :                                         missionTextRow = 0;
    4974             :                                         [self setGuiToScenarioScreen:0];
    4975             :                                 } 
    4976             :                                 else if (([gameView isDown:gvMouseDoubleClick] || [self checkKeyPress:n_key_gui_select]) && [gui selectedRow] == 3+row_zero)
    4977             :                                 {
    4978             :                                         [self setGuiToIntroFirstGo:NO];
    4979             :                                 }
    4980             :                                 else if (([gameView isDown:gvMouseDoubleClick] || [self checkKeyPress:n_key_gui_select]) && [gui selectedRow] == 4+row_zero)
    4981             :                                 {
    4982             :                                         [self setGuiToGameOptionsScreen];
    4983             :                                 }
    4984             :                                 else if (([gameView isDown:gvMouseDoubleClick] || [self checkKeyPress:n_key_gui_select]) && [gui selectedRow] == 5+row_zero)
    4985             :                                 {
    4986             :                                         [self setGuiToOXZManager];
    4987             :                                 }
    4988             :                                 else if (([gameView isDown:gvMouseDoubleClick] || [self checkKeyPress:n_key_gui_select]) && [gui selectedRow] == 6+row_zero)
    4989             :                                 {
    4990             :                                         [[UNIVERSE gameController] exitAppWithContext:@"Exit Game selected on start screen"];
    4991             :                                 }
    4992             :                                 else
    4993             :                                 {
    4994             :                                         disc_operation_in_progress = NO;
    4995             :                                 }
    4996             :                         }
    4997             :                         selectPressed = [self checkKeyPress:n_key_gui_select];
    4998             :                         if ([gameView isDown:gvMouseDoubleClick])
    4999             :                         {
    5000             :                                 [gameView clearMouse];
    5001             :                         }
    5002             :                         break;
    5003             :                         
    5004             :                 case GUI_SCREEN_GAMEOPTIONS:
    5005             :                         [self handleGameOptionsScreenKeys];
    5006             :                         break;
    5007             :                         
    5008             :                 case GUI_SCREEN_KEYBOARD:
    5009             :                         //if ([gameView isDown:' '])    //  '<space>'
    5010             :                         //{
    5011             :                         //      [self setGuiToIntroFirstGo:YES];
    5012             :                         //}
    5013             :                         [self handleKeyMapperScreenKeys];
    5014             :                         break;
    5015             : 
    5016             :                 case GUI_SCREEN_KEYBOARD_CONFIRMCLEAR:
    5017             :                         [self handleKeyMapperConfirmClearKeys:gui view:gameView];
    5018             :                         break;
    5019             : 
    5020             :                 case GUI_SCREEN_KEYBOARD_CONFIG:
    5021             :                         [self handleKeyConfigKeys:gui view:gameView];
    5022             :                         break;
    5023             : 
    5024             :                 case GUI_SCREEN_KEYBOARD_ENTRY:
    5025             :                         [self handleKeyConfigEntryKeys:gui view:gameView];
    5026             :                         break;
    5027             : 
    5028             :                 case GUI_SCREEN_KEYBOARD_LAYOUT:
    5029             :                         [self handleKeyboardLayoutKeys];
    5030             :                         break;
    5031             : 
    5032             :                 case GUI_SCREEN_STICKMAPPER:
    5033             :                         [self handleStickMapperScreenKeys];
    5034             :                         break;
    5035             :                         
    5036             :                 case GUI_SCREEN_STICKPROFILE:
    5037             :                         [self stickProfileInputHandler:gui view:gameView];
    5038             :                         break;
    5039             : 
    5040             :                 case GUI_SCREEN_SHIPLIBRARY:
    5041             :                         if ([gameView isDown:' '])      //  '<space>'
    5042             :                         {
    5043             :                                 // viewed from start screen, return to it
    5044             :                                 [self setGuiToIntroFirstGo:YES];
    5045             :                         }
    5046             :                         if ([self checkKeyPress:n_key_gui_arrow_up])    //  '<--'
    5047             :                         {
    5048             :                                 if (!upDownKeyPressed)
    5049             :                                         [UNIVERSE selectIntro2Previous];
    5050             :                         }
    5051             :                         if ([self checkKeyPress:n_key_gui_arrow_down])  //  '-->'
    5052             :                         {
    5053             :                                 if (!upDownKeyPressed)
    5054             :                                         [UNIVERSE selectIntro2Next];
    5055             :                         }
    5056             :                         upDownKeyPressed = (([self checkKeyPress:n_key_gui_arrow_up])||([self checkKeyPress:n_key_gui_arrow_down]));
    5057             : 
    5058             :                         if ([self checkKeyPress:n_key_gui_arrow_left])  //  '<--'
    5059             :                         {
    5060             :                                 if (!leftRightKeyPressed)
    5061             :                                         [UNIVERSE selectIntro2PreviousCategory];
    5062             :                         }
    5063             :                         if ([self checkKeyPress:n_key_gui_arrow_right]) //  '-->'
    5064             :                         {
    5065             :                                 if (!leftRightKeyPressed)
    5066             :                                         [UNIVERSE selectIntro2NextCategory];
    5067             :                         }
    5068             :                         leftRightKeyPressed = (([self checkKeyPress:n_key_gui_arrow_left])||([self checkKeyPress:n_key_gui_arrow_right]));
    5069             :                         
    5070             : 
    5071             :                         break;
    5072             :                 
    5073             :                 case GUI_SCREEN_NEWGAME:
    5074             :                         if ([self handleGUIUpDownArrowKeys])
    5075             :                         {
    5076             :                                 [self showScenarioDetails];
    5077             :                         }
    5078             : 
    5079             :                         if (!pageUpDownKeyPressed) 
    5080             :                         {
    5081             :                                 if ([self checkKeyPress:n_key_gui_page_up])
    5082             :                                 {
    5083             :                                         //  find the Back <<< line, select it and press it
    5084             :                                         if ([[gui keyForRow:GUI_ROW_SCENARIOS_START - 1] hasPrefix:@"__page"]) 
    5085             :                                         {
    5086             :                                                 if ([gui setSelectedRow:GUI_ROW_SCENARIOS_START - 1]) 
    5087             :                                                 {
    5088             :                                                         [self startScenario];
    5089             :                                                 }
    5090             :                                         }
    5091             : 
    5092             :                                 }
    5093             :                                 else if ([self checkKeyPress:n_key_gui_page_down])
    5094             :                                 {
    5095             :                                         // find the Next >>> line, select it and press it
    5096             :                                         if ([[gui keyForRow:GUI_ROW_SCENARIOS_START + GUI_MAX_ROWS_SCENARIOS] hasPrefix:@"__page"]) 
    5097             :                                         {
    5098             :                                                 if ([gui setSelectedRow:GUI_ROW_SCENARIOS_START + GUI_MAX_ROWS_SCENARIOS]) 
    5099             :                                                 {
    5100             :                                                         [self startScenario];
    5101             :                                                 }
    5102             :                                         }
    5103             :                                 }
    5104             :                         }
    5105             :                         pageUpDownKeyPressed = [self checkKeyPress:n_key_gui_page_down]|[self checkKeyPress:n_key_gui_page_up];
    5106             : 
    5107             :                         if (!selectPressed)
    5108             :                         {
    5109             :                                 if ([self checkKeyPress:n_key_gui_select] || [gameView isDown:gvMouseDoubleClick]) // enter
    5110             :                                 {
    5111             :                                         if (![self startScenario])
    5112             :                                         {
    5113             :                                                 [UNIVERSE removeDemoShips];
    5114             :                                                 [self setGuiToIntroFirstGo:YES];
    5115             :                                         } 
    5116             :                                 }
    5117             :                         }
    5118             :                         selectPressed = [self checkKeyPress:n_key_gui_select];
    5119             :                         if ([gameView isDown:gvMouseDoubleClick] || [gameView isDown:gvMouseLeftButton])
    5120             :                         {
    5121             :                                 [gameView clearMouse];
    5122             :                         }
    5123             :                         break;
    5124             : 
    5125             :                 case GUI_SCREEN_OXZMANAGER:
    5126             :                         // release locks on music on this screen
    5127             :                         [[OOMusicController sharedController] stopThemeMusic];
    5128             :                         if (EXPECT(![oxzmanager isRestarting]))
    5129             :                         {
    5130             :                                 if ([oxzmanager isAcceptingGUIInput])
    5131             :                                 {
    5132             :                                         if ([oxzmanager isAcceptingTextInput])
    5133             :                                         {
    5134             :                                                 [gameView setStringInput: gvStringInputAll];
    5135             :                                                 [oxzmanager refreshTextInput:[gameView typedString]];
    5136             :                                         }
    5137             :                                         else
    5138             :                                         {
    5139             :                                                 [gameView allowStringInput: NO];
    5140             :                                         }
    5141             :                                         if ([self handleGUIUpDownArrowKeys])
    5142             :                                         {
    5143             :                                                 // only has an effect on install/remove selection screens
    5144             :                                                 [oxzmanager showOptionsUpdate];
    5145             :                                         }
    5146             :                                         if ([self checkKeyPress:n_key_gui_arrow_left] || [self checkKeyPress:n_key_gui_page_up])
    5147             :                                         {
    5148             :                                                 if ((!leftRightKeyPressed))
    5149             :                                                 {
    5150             :                                                         [oxzmanager processOptionsPrev];
    5151             :                                                 }
    5152             :                                         }
    5153             :                                         else if ([self checkKeyPress:n_key_gui_arrow_right] || [self checkKeyPress:n_key_gui_page_down])
    5154             :                                         {
    5155             :                                                 if ((!leftRightKeyPressed))
    5156             :                                                 {
    5157             :                                                         [oxzmanager processOptionsNext];
    5158             :                                                 }
    5159             :                                         }
    5160             :                                         leftRightKeyPressed = [self checkKeyPress:n_key_gui_arrow_right]|[self checkKeyPress:n_key_gui_arrow_left]|[self checkKeyPress:n_key_gui_page_down]|[self checkKeyPress:n_key_gui_page_up];
    5161             : 
    5162             :                                         if (!selectPressed)
    5163             :                                         {
    5164             :                                                 if ([self checkKeyPress:n_key_gui_select] || [gameView isDown:gvMouseDoubleClick]) // enter
    5165             :                                                 {
    5166             :                                                         if ([oxzmanager isAcceptingTextInput])
    5167             :                                                         {
    5168             :                                                                 [oxzmanager processTextInput:[gameView typedString]];
    5169             :                                                         }
    5170             :                                                         else
    5171             :                                                         {
    5172             :                                                                 [oxzmanager processSelection];
    5173             :                                                         }
    5174             :                                                 }
    5175             :                                         }
    5176             :                                         selectPressed = [self checkKeyPress:n_key_gui_select];
    5177             :                                         if ([gameView isDown:gvMouseDoubleClick] || [gameView isDown:gvMouseLeftButton])
    5178             :                                         {
    5179             :                                                 [gameView clearMouse];
    5180             :                                         }
    5181             :                                 } // endif isAcceptingGUIInput
    5182             :                                 if ([self checkKeyPress:n_key_oxzmanager_setfilter] ||
    5183             :                                         [self checkKeyPress:n_key_oxzmanager_showinfo] ||
    5184             :                                         [self checkKeyPress:n_key_oxzmanager_extract])
    5185             :                                 {
    5186             :                                         if (!oxz_manager_pressed)
    5187             :                                         {
    5188             :                                                 oxz_manager_pressed = YES;
    5189             :                                                 if ([self checkKeyPress:n_key_oxzmanager_setfilter])
    5190             :                                                 {
    5191             :                                                         [oxzmanager processFilterKey];
    5192             :                                                 }
    5193             :                                                 else if ([self checkKeyPress:n_key_oxzmanager_showinfo])
    5194             :                                                 {
    5195             :                                                         [oxzmanager processShowInfoKey];
    5196             :                                                 }
    5197             :                                                 else if ([self checkKeyPress:n_key_oxzmanager_extract])
    5198             :                                                 {
    5199             :                                                         [oxzmanager processExtractKey];
    5200             :                                                 }
    5201             :                                                 
    5202             :                                         }
    5203             :                                 }
    5204             :                                 else
    5205             :                                 {
    5206             :                                         oxz_manager_pressed = NO;
    5207             :                                 }
    5208             :                         }
    5209             :                         break;
    5210             :         
    5211             : 
    5212             :         
    5213             :                 case GUI_SCREEN_MISSION:
    5214             :                         if ([[self hud] allowBigGui])
    5215             :                         {
    5216             :                                 end_row = 27;
    5217             :                         }
    5218             :                         if (_missionTextEntry)
    5219             :                         {
    5220             :                                 [self refreshMissionScreenTextEntry];
    5221             :                                 if ([self checkKeyPress:n_key_gui_select] || [gameView isDown:gvMouseDoubleClick])      //  '<enter/return>' or double click
    5222             :                                 {
    5223             :                                         [self setMissionChoice:[gameView typedString] keyPress:@"enter"];
    5224             :                                         [[OOMusicController sharedController] stopMissionMusic];
    5225             :                                         [self playDismissedMissionScreen];
    5226             :                                         
    5227             :                                         [self handleMissionCallback];
    5228             :                                         
    5229             :                                         [self checkScript];
    5230             :                                         selectPressed = YES;
    5231             :                                         pollControls = YES;
    5232             :                                 }
    5233             :                                 else
    5234             :                                 {
    5235             :                                         pollControls = NO;
    5236             :                                         selectPressed = NO;
    5237             :                                         [self pollMissionInterruptControls];
    5238             :                                 }
    5239             :                         }
    5240             :                         else if ([[gui keyForRow:end_row] isEqual:@"spacebar"])
    5241             :                         {
    5242             :                                 if ([gameView isDown:32])       //  '<space>'
    5243             :                                 {
    5244             :                                         if (!spacePressed)
    5245             :                                         {
    5246             :                                                 [[OOMusicController sharedController] stopMissionMusic];
    5247             :                                                 [self handleMissionCallback];
    5248             :                                                 
    5249             :                                         }
    5250             :                                         spacePressed = YES;
    5251             :                                 }
    5252             :                                 else
    5253             :                                 {
    5254             :                                         spacePressed = NO;
    5255             :                                         [self pollMissionInterruptControls];
    5256             :                                 }
    5257             :                         }
    5258             :                         else
    5259             :                         {
    5260             :                                 [self handleGUIUpDownArrowKeys];
    5261             :                                 NSString *extraKey = @"";
    5262             :                                 if (extraMissionKeys)
    5263             :                                 {
    5264             :                                         NSString *key = nil;
    5265             :                                         foreach (key, [extraMissionKeys allKeys])
    5266             :                                         {
    5267             :                                                 if ([self checkKeyPress:[extraMissionKeys oo_arrayForKey:key]]) {
    5268             :                                                         if (!extra_key_pressed)
    5269             :                                                         {
    5270             :                                                                 extraKey = [key copy];
    5271             :                                                         }
    5272             :                                                         extra_key_pressed = YES;
    5273             :                                                 }
    5274             :                                                 else
    5275             :                                                 extra_key_pressed = NO;
    5276             :                                         }
    5277             :                                 }
    5278             :                                 if ([self checkKeyPress:n_key_gui_select] || [gameView isDown:gvMouseDoubleClick] || [extraKey length] > 0)  //  '<enter/return>' or double click
    5279             :                                 {
    5280             :                                         if ([gameView isDown:gvMouseDoubleClick])
    5281             :                                         {
    5282             :                                                 selectPressed = NO;
    5283             :                                                 [gameView clearMouse];
    5284             :                                         }
    5285             :                                         if (!selectPressed)
    5286             :                                         {
    5287             :                                                 if ([extraKey length] == 0) extraKey = @"enter";
    5288             :                                                 [self setMissionChoice:[gui selectedRowKey] keyPress:extraKey];
    5289             :                                                 [[OOMusicController sharedController] stopMissionMusic];
    5290             :                                                 [self playDismissedMissionScreen];
    5291             :                                                 
    5292             :                                                 [self handleMissionCallback];
    5293             :                                                 
    5294             :                                                 [self checkScript];
    5295             :                                         }
    5296             :                                         selectPressed = YES;
    5297             :                                 }
    5298             :                                 else
    5299             :                                 {
    5300             :                                         selectPressed = NO;
    5301             :                                         [self pollMissionInterruptControls];
    5302             :                                 }
    5303             :                                 [extraKey release];
    5304             :                         }
    5305             :                         break;
    5306             :                         
    5307             : #if OO_USE_CUSTOM_LOAD_SAVE
    5308             :                         // DJS: Farm off load/save screen options to LoadSave.m
    5309             :                 case GUI_SCREEN_LOAD:
    5310             :                 {
    5311             :                         NSString *commanderFile = [self commanderSelector];
    5312             :                         if(commanderFile)
    5313             :                         {
    5314             :                                 // also release the demo ship here (see showShipyardModel and noteGUIDidChangeFrom)
    5315             :                                 [demoShip release];
    5316             :                                 demoShip = nil;
    5317             :                                 
    5318             :                                 [self loadPlayerFromFile:commanderFile asNew:NO];
    5319             :                         }
    5320             :                         break;
    5321             :                 }
    5322             : #endif
    5323             : 
    5324             :                 default:
    5325             :                         break;
    5326             :         }
    5327             : }
    5328             : 
    5329             : 
    5330             : - (void) pollMissionInterruptControls
    5331             : {
    5332             :         if (_missionAllowInterrupt)
    5333             :         {
    5334             :                 if (gui_screen == GUI_SCREEN_MISSION && _missionTextEntry) 
    5335             :                 {
    5336             :                         [self pollGuiScreenControlsWithFKeyAlias:NO];
    5337             :                 }
    5338             :                 else {
    5339             :                         [self pollGuiScreenControls];
    5340             :                 }
    5341             :                 if (gui_screen != GUI_SCREEN_MISSION)
    5342             :                 {
    5343             :                         if (gui_screen != GUI_SCREEN_SYSTEM_DATA)
    5344             :                         {
    5345             :                                 [UNIVERSE removeDemoShips];
    5346             :                         }
    5347             :                         [self endMissionScreenAndNoteOpportunity];
    5348             :                 }
    5349             :         }
    5350             : }
    5351             : 
    5352             : 
    5353             : - (void) handleMissionCallback
    5354             : {
    5355             :         [UNIVERSE removeDemoShips];
    5356             :         [[UNIVERSE gui] clearBackground];
    5357             : 
    5358             :         [self setGuiToMissionEndScreen]; // need this to find out if we call a new mission screen inside callback.
    5359             :         
    5360             :         if ([self status] != STATUS_DOCKED) [self switchToThisView:VIEW_FORWARD];
    5361             : 
    5362             :         if (_missionWithCallback)
    5363             :         {
    5364             :                 [self doMissionCallback];
    5365             :         }
    5366             :         
    5367             :         if ([self status] != STATUS_DOCKED)     // did we launch inside callback? / are we in flight?
    5368             :         {
    5369             :                 // TODO: This is no longer doing anything because of an 'isDocked' check inside the function. ***** Probably remove it for 1.76
    5370             :                 [self doWorldEventUntilMissionScreen:OOJSID("missionScreenEnded")];   // no opportunity events.
    5371             :         }
    5372             :         else
    5373             :         {
    5374             :                 if (gui_screen != GUI_SCREEN_MISSION) // did we call a new mission screen inside callback?
    5375             :                 {
    5376             :                         // note that this might not be the same end screen as last time...
    5377             :                         [self setGuiToMissionEndScreen];        // if not, update status screen with callback changes, if any.
    5378             :                         [self endMissionScreenAndNoteOpportunity];      // missionScreenEnded, plus opportunity events.
    5379             :                 }
    5380             :         }
    5381             : }
    5382             : 
    5383             : 
    5384             : - (void) setGuiToMissionEndScreen
    5385             : {
    5386             :         MyOpenGLView    *gameView = [UNIVERSE gameView];
    5387             :         [gameView clearKeys];
    5388             :         if ([self status] != STATUS_DOCKED)
    5389             :         {
    5390             :                 // this setting is only applied when not docked
    5391             :                 [self setGuiToStatusScreen];
    5392             :                 return;
    5393             :         }
    5394             :         switch (_missionExitScreen)
    5395             :         {
    5396             :         case GUI_SCREEN_MANIFEST:
    5397             :                 [self noteGUIWillChangeTo:GUI_SCREEN_MANIFEST];
    5398             :                 [self setGuiToManifestScreen];
    5399             :                 break;
    5400             :         case GUI_SCREEN_EQUIP_SHIP:
    5401             :                 [self noteGUIWillChangeTo:GUI_SCREEN_EQUIP_SHIP];
    5402             :                 [self setGuiToEquipShipScreen:0];
    5403             :                 break;
    5404             :         case GUI_SCREEN_SHIPYARD:
    5405             :                 if ([[self dockedStation] hasShipyard])
    5406             :                 {
    5407             :                         [self noteGUIWillChangeTo:GUI_SCREEN_SHIPYARD];
    5408             :                         [self setGuiToShipyardScreen:0];
    5409             :                         [[UNIVERSE gui] setSelectedRow:GUI_ROW_SHIPYARD_START];
    5410             :                         [self showShipyardInfoForSelection];
    5411             :                 }
    5412             :                 else
    5413             :                 {
    5414             :                         // that doesn't work here
    5415             :                         [self setGuiToStatusScreen];
    5416             :                 }
    5417             :                 break;
    5418             :         case GUI_SCREEN_LONG_RANGE_CHART:
    5419             :                 [self setGuiToLongRangeChartScreen];
    5420             :                 break;
    5421             :         case GUI_SCREEN_SHORT_RANGE_CHART:
    5422             :                 [self setGuiToShortRangeChartScreen];
    5423             :                 break;
    5424             :         case GUI_SCREEN_SYSTEM_DATA:
    5425             :                 [self noteGUIWillChangeTo:GUI_SCREEN_SYSTEM_DATA];
    5426             :                 [self setGuiToSystemDataScreen];
    5427             :                 break;
    5428             :         case GUI_SCREEN_MARKET:
    5429             :                 [self noteGUIWillChangeTo:GUI_SCREEN_MARKET];
    5430             :                 [self setGuiToMarketScreen];
    5431             :                 break;
    5432             :         case GUI_SCREEN_MARKETINFO:
    5433             :                 [self noteGUIWillChangeTo:GUI_SCREEN_MARKETINFO];
    5434             :                 [self setGuiToMarketInfoScreen];
    5435             :                 break;
    5436             :         case GUI_SCREEN_INTERFACES:
    5437             :                 [self setGuiToInterfacesScreen:0];
    5438             :                 break;
    5439             :         case GUI_SCREEN_STATUS:
    5440             :         default: // invalid screen specifications
    5441             :                 [self setGuiToStatusScreen];
    5442             :         }
    5443             : }
    5444             : 
    5445             : 
    5446             : - (void) switchToThisView:(OOViewID)viewDirection
    5447             : {
    5448             :         [self switchToThisView:viewDirection andProcessWeaponFacing:YES];
    5449             : }
    5450             : 
    5451             : 
    5452             : - (void) switchToThisView:(OOViewID)viewDirection andProcessWeaponFacing:(BOOL)processWeaponFacing
    5453             : {
    5454             :         [self switchToThisView:viewDirection fromView:[UNIVERSE viewDirection] andProcessWeaponFacing:processWeaponFacing justNotify:NO];
    5455             : }
    5456             : 
    5457             : 
    5458             : - (void) switchToThisView:(OOViewID)viewDirection fromView:(OOViewID)oldViewDirection andProcessWeaponFacing:(BOOL)processWeaponFacing justNotify:(BOOL)justNotify
    5459             : {
    5460             :         if (!justNotify)
    5461             :         {       
    5462             :                 if ([UNIVERSE displayGUI]) [self switchToMainView];
    5463             :                 [UNIVERSE setViewDirection:viewDirection];
    5464             :         }
    5465             :         if (processWeaponFacing)
    5466             :         {
    5467             :                 OOWeaponFacing facing = WEAPON_FACING_NONE;
    5468             :                 switch (viewDirection)
    5469             :                 {
    5470             :                         case VIEW_FORWARD:
    5471             :                                 facing = WEAPON_FACING_FORWARD;
    5472             :                                 break;
    5473             :                                 
    5474             :                         case VIEW_AFT:
    5475             :                                 facing = WEAPON_FACING_AFT;
    5476             :                                 break;
    5477             :                                 
    5478             :                         case VIEW_PORT:
    5479             :                                 facing = WEAPON_FACING_PORT;
    5480             :                                 break;
    5481             :                                 
    5482             :                         case VIEW_STARBOARD:
    5483             :                                 facing = WEAPON_FACING_STARBOARD;
    5484             :                                 break;
    5485             :                                 
    5486             :                         default:
    5487             :                                 break;
    5488             :                 }
    5489             :                 
    5490             :                 if (facing != WEAPON_FACING_NONE)
    5491             :                 {
    5492             :                         currentWeaponFacing = facing;
    5493             :                         [self currentWeaponStats];
    5494             :                 }
    5495             :                 else
    5496             :                 {
    5497             :                         OOLogERR(kOOLogParameterError, @"%s called with processWeaponFacing=YES for non-main view %i.", __FUNCTION__, viewDirection);
    5498             :                 }
    5499             :         }
    5500             :         if ((oldViewDirection != viewDirection || viewDirection == VIEW_CUSTOM) && ![[UNIVERSE gameController] isGamePaused])
    5501             :         {
    5502             :                 JSContext *context = OOJSAcquireContext();
    5503             :                 ShipScriptEvent(context, self, "viewDirectionChanged", OOJSValueFromViewID(context, viewDirection), OOJSValueFromViewID(context, oldViewDirection));
    5504             :                 OOJSRelinquishContext(context);
    5505             :         }
    5506             : }
    5507             : 
    5508             : 
    5509             : // Called on c or Shift-C
    5510             : - (void) handleAutopilotOn:(BOOL)fastDocking
    5511             : {
    5512             :         NSString        *message = nil;
    5513             :         
    5514             :         // Check alert condition - on red alert, abort
    5515             :         // -- but only for fast docking
    5516             :         if (fastDocking && ([self alertCondition] == ALERT_CONDITION_RED))
    5517             :         {
    5518             :                 [self playAutopilotCannotDockWithTarget];
    5519             :                 message = OOExpandKey(@"autopilot-red-alert");
    5520             :                 goto abort;
    5521             :         }
    5522             :         
    5523             :         Entity *target = [self primaryTarget];
    5524             :         // If target isn't dockable, check for nearby stations
    5525             :         if (![target isStation])
    5526             :         {
    5527             :                 Universe  *uni        = UNIVERSE;
    5528             :                 Entity    **entities  = uni->sortedEntities; // grab the public sorted list
    5529             :                 int       nStations   = 0;
    5530             :                 unsigned  i;
    5531             :                 
    5532             :                 for (i = 0; i < uni->n_entities && nStations < 2; i++)
    5533             :                 {
    5534             :                         if (entities[i]->isStation && [entities[i] isKindOfClass:[StationEntity class]] &&
    5535             :                                 entities[i]->zero_distance <= SCANNER_MAX_RANGE2)
    5536             :                         {
    5537             :                                 nStations++;
    5538             :                                 target = entities[i];
    5539             :                         }
    5540             :                 }
    5541             :                 // If inside the Aegis, dock with the main station.
    5542             :                 // If we found one target, dock with it.
    5543             :                 // If outside the Aegis and we found multiple targets, abort.
    5544             :                 
    5545             :                 if ([self withinStationAegis] && legalStatus <= 50)
    5546             :                 {
    5547             :                         target = [UNIVERSE station];
    5548             :                 }
    5549             :                 else if (nStations != 1)
    5550             :                 {
    5551             :                         if (nStations == 0)
    5552             :                         {
    5553             :                                 [self playAutopilotOutOfRange];
    5554             :                                 message = OOExpandKey(@"autopilot-out-of-range");
    5555             :                         }
    5556             :                         else
    5557             :                         {
    5558             :                                 [self playAutopilotCannotDockWithTarget];
    5559             :                                 message = OOExpandKey(@"autopilot-multiple-targets");
    5560             :                         }
    5561             :                         goto abort;
    5562             :                 }
    5563             :         }
    5564             :         
    5565             :         // We found a dockable, check whether we can dock with it
    5566             :         // NSAssert([target isKindOfClass:[StationEntity class]], @"Expected entity with isStation flag set to be a station.");               // no need for asserts. Tested enough already.
    5567             :         StationEntity *ts = (StationEntity *)target;
    5568             :         NSString *stationName = [ts displayName];
    5569             :         
    5570             :         // If station is not transmitting docking instructions, we cannot use autopilot.
    5571             :         if (![ts allowsAutoDocking])
    5572             :         {
    5573             :                 [self playAutopilotCannotDockWithTarget];
    5574             :                 message = OOExpandKey(@"autopilot-station-does-not-allow-autodocking", stationName);
    5575             :         }
    5576             :         // Deny if station is hostile or player is a fugitive trying to dock at the main station.
    5577             :         else if ((legalStatus > 50 && ts == [UNIVERSE station]) || [ts isHostileTo:self])
    5578             :         {
    5579             :                 [self playAutopilotCannotDockWithTarget];
    5580             :                 message = OOExpandKey((ts == [UNIVERSE station]) ? @"autopilot-denied" : @"autopilot-target-docking-instructions-denied", stationName);
    5581             :         }
    5582             :         // If we're fast-docking, perform the docking logic
    5583             :         else if (fastDocking && [ts allowsFastDocking])
    5584             :         {
    5585             :                 // check whether there are docks that do not accept docking - even one such dock will result in rejection
    5586             :                 NSEnumerator    *subEnum = nil;
    5587             :                 DockEntity* sub = nil;
    5588             :                 for (subEnum = [ts dockSubEntityEnumerator]; (sub = [subEnum nextObject]); )
    5589             :                 {
    5590             :                         // TOO_BIG_TO_DOCK issued when docks are scripted to reject docking
    5591             :                         if([[sub canAcceptShipForDocking:self] isEqualToString:@"TOO_BIG_TO_DOCK"]) 
    5592             :                         {
    5593             :                                 message = OOExpandKey((ts == [UNIVERSE station]) ? @"autopilot-denied" : @"autopilot-target-docking-instructions-denied", stationName);
    5594             :                                 goto abort;
    5595             :                         }
    5596             :                 }
    5597             :         
    5598             :                 if (legalStatus > 0)
    5599             :                 {
    5600             :                         // there's a slight chance you'll be fined for your past offences when autodocking
    5601             :                         int fine_chance = ranrot_rand() & 0x03ff;   //      0..1023
    5602             :                         int government = 1 + [[UNIVERSE currentSystemData] oo_intForKey:KEY_GOVERNMENT];        // 1..8
    5603             :                         if ([UNIVERSE inInterstellarSpace])  government = 2;    // equivalent to Feudal. I'm assuming any station in interstellar space is military. -- Ahruman 2008-05-29
    5604             :                         fine_chance /= government;
    5605             :                         if (fine_chance < legalStatus)
    5606             :                         {
    5607             :                                 [self markForFines];
    5608             :                         }
    5609             :                 }
    5610             :                 
    5611             :                 [self setDockingClearanceStatus:DOCKING_CLEARANCE_STATUS_GRANTED];
    5612             :                 
    5613             :                 [UNIVERSE forceWitchspaceEntries];
    5614             :                 ship_clock_adjust += 1200.0;                    // 20 minutes penalty to enter dock
    5615             :                 ident_engaged = NO;
    5616             :                 [self safeAllMissiles];
    5617             :                 [UNIVERSE setViewDirection:VIEW_FORWARD];
    5618             :                 [self enterDock:ts];
    5619             :         }
    5620             :         else
    5621             :         {
    5622             :                 // Standard docking - engage autopilot
    5623             :                 [self engageAutopilotToStation:ts];
    5624             :                 message = OOExpandKey(@"autopilot-on");
    5625             :         }
    5626             :         
    5627             : abort:
    5628             :         // Clean-up code
    5629             :         if (message != nil) [UNIVERSE addMessage:message forCount:4.5];
    5630             :         return;
    5631             : }
    5632             : 
    5633             : 
    5634             : - (void) handleButtonIdent
    5635             : {
    5636             :         // Clear current target if we're already in Ident mode
    5637             :         if (ident_engaged)  [self noteLostTarget];
    5638             :         
    5639             :         [self safeAllMissiles];
    5640             :         ident_engaged = YES;
    5641             :         if ([self primaryTarget] == nil)
    5642             :         {
    5643             :                 [self playIdentOn];
    5644             :                 [UNIVERSE addMessage:OOExpandKey(@"ident-on") forCount:2.0];
    5645             :         }
    5646             :         else
    5647             :         {
    5648             :                 [self playIdentLockedOn];
    5649             :                 [self printIdentLockedOnForMissile:NO];
    5650             :         }
    5651             : }
    5652             : 
    5653             : 
    5654             : - (void) handleButtonTargetMissile
    5655             : {
    5656             :         if (![self weaponsOnline])
    5657             :         {
    5658             :                 [self handleButtonIdent];
    5659             :                 return;
    5660             :         }
    5661             :         
    5662             :         // Clear current target if we're already in Missile Targeting mode
    5663             :         if (missile_status != MISSILE_STATUS_SAFE)
    5664             :         {
    5665             :                 [self noteLostTarget];
    5666             :         }
    5667             :         
    5668             :         // Arm missile and check for missile lock
    5669             :         missile_status = MISSILE_STATUS_ARMED;
    5670             :         if ([missile_entity[activeMissile] isMissile])
    5671             :         {
    5672             :                 if ([[self primaryTarget] isShip])
    5673             :                 {
    5674             :                         missile_status = MISSILE_STATUS_TARGET_LOCKED;
    5675             :                         [missile_entity[activeMissile] addTarget:[self primaryTarget]];
    5676             :                         [self printIdentLockedOnForMissile:YES];
    5677             :                         [self playMissileLockedOn];
    5678             :                 }
    5679             :                 else
    5680             :                 {
    5681             :                         // if it's nil, that means it was lost earlier
    5682             :                         if ([self primaryTarget] != nil)
    5683             :                         {
    5684             :                                 [self noteLostTarget];
    5685             :                         }
    5686             :                         [missile_entity[activeMissile] noteLostTarget];
    5687             :                         NSString *weaponName = [missile_entity[activeMissile] name];
    5688             :                         [UNIVERSE addMessage:OOExpandKey(@"missile-armed", weaponName) forCount:2.0];
    5689             :                         [self playMissileArmed];
    5690             :                 }
    5691             :         }
    5692             :         else if ([missile_entity[activeMissile] isMine])
    5693             :         {
    5694             :                 NSString *weaponName = [missile_entity[activeMissile] name];
    5695             :                 [UNIVERSE addMessage:OOExpandKey(@"mine-armed", weaponName) forCount:2.0];
    5696             :                 [self playMineArmed];
    5697             :         }
    5698             :         ident_engaged = NO;
    5699             : }
    5700             : 
    5701             : @end

Generated by: LCOV version 1.14