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