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