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