Oolite 1.91.0.7604-240417-a536cbe
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
112static BOOL speech_settings_pressed;
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
915- (void) pollApplicationControls
916{
917 if (!pollControls) return;
918
919 NSString *exceptionContext = @"setup";
920
921 // does fullscreen / quit / snapshot
922 MyOpenGLView *gameView = [UNIVERSE gameView];
923 GameController *gameController = [UNIVERSE gameController];
924
925 BOOL onTextEntryScreen = (gui_screen == GUI_SCREEN_LONG_RANGE_CHART) || (gui_screen == GUI_SCREEN_MISSION) ||
926 (gui_screen == GUI_SCREEN_SAVE) || (gui_screen == GUI_SCREEN_OXZMANAGER || (gui_screen == GUI_SCREEN_KEYBOARD_ENTRY));
927
928 @try
929 {
930 // command-key controls
931 #if !OOLITE_MAC_OS_X || !OOLITE_64_BIT // On 64-bit Macs, these are handled by normal menu shortcuts.
932 if ([gameController inFullScreenMode])
933 {
934 exceptionContext = @"command key controls";
935 if ([gameView isCommandFDown])
936 {
937 [gameView clearCommandF];
938 [gameController exitFullScreenMode];
939 if (mouse_control_on)
940 {
941 [UNIVERSE addMessage:DESC(@"mouse-off") forCount:3.0];
942 mouse_control_on = NO;
943 }
944 }
945
946 if ([gameView isCommandQDown])
947 {
948 [gameController pauseFullScreenModeToPerform:@selector(exitAppCommandQ) onTarget:gameController];
949 }
950 }
951 #endif
952
953 // handle pressing Q or [esc] in error-handling mode
954 if ([self status] == STATUS_HANDLING_ERROR)
955 {
956 exceptionContext = @"error handling mode";
957 if ([gameView isDown:113]||[gameView isDown:81]||[gameView isDown:27]) // 'q' | 'Q' | esc
958 {
959 [gameController exitAppWithContext:@"Q or escape pressed in error handling mode"];
960 }
961 }
962
963 if ([gameController isGamePaused])
964 {
965 // What's the status?
966 switch ([self status])
967 {
968 case STATUS_WITCHSPACE_COUNTDOWN:
969 case STATUS_IN_FLIGHT:
970 case STATUS_AUTOPILOT_ENGAGED:
971 case STATUS_DOCKED:
972 // Pause is handled inside their pollControls, no need to unpause.
973 break;
974
975 default:
976 {
977 // In all other cases we can't handle pause. Unpause immediately.
978 script_time = saved_script_time;
979 [gameView allowStringInput:NO];
980 if ([UNIVERSE pauseMessageVisible])
981 {
982 [UNIVERSE clearPreviousMessage]; // remove the 'paused' message.
983 }
984 [gameController setGamePaused:NO];
985 }
986 break;
987 }
988
989 }
990
991 // snapshot
992 const BOOL *joyButtonState = [[OOJoystickManager sharedStickHandler] getAllButtonStates];
993
994 if (([self checkKeyPress:n_key_snapshot] || joyButtonState[BUTTON_SNAPSHOT]) &&
995 ([gameView allowingStringInput] <= gvStringInputAlpha) && // not while entering text on the keyboard config screens
996 ![[OOOXZManager sharedManager] isAcceptingTextInput]) // '*' key but not while filtering inside OXZ Manager
997 {
998 exceptionContext = @"snapshot";
999 if (!taking_snapshot)
1000 {
1001 taking_snapshot = YES;
1002 [gameView snapShot:nil]; // nil filename so that the program auto-names the snapshot
1003 }
1004 }
1005 else
1006 {
1007 taking_snapshot = NO;
1008 }
1009
1010 // FPS display
1011 if (!onTextEntryScreen && [self checkKeyPress:n_key_show_fps]) // 'F' key
1012 {
1013 exceptionContext = @"toggle FPS";
1014 if (!f_key_pressed) [UNIVERSE setDisplayFPS:![UNIVERSE displayFPS]];
1015 f_key_pressed = YES;
1016 }
1017 else
1018 {
1019 f_key_pressed = NO;
1020 }
1021
1022 // bloom toggle
1023 if ([self checkKeyPress:n_key_bloom_toggle])
1024 {
1025 if (!f9_key_pressed)
1026 {
1027 BOOL oldBloom = [UNIVERSE bloom];
1028 [UNIVERSE setBloom:!oldBloom];
1029 }
1030 f9_key_pressed = YES;
1031 }
1032 else
1033 {
1034 f9_key_pressed = NO;
1035 }
1036
1037 // Mouse control
1038 BOOL allowMouseControl;
1039 #if OO_DEBUG
1040 allowMouseControl = YES;
1041 #else
1042 allowMouseControl = [gameController inFullScreenMode] ||
1043 [[NSUserDefaults standardUserDefaults] boolForKey:@"mouse-control-in-windowed-mode"];
1044 #endif
1045
1046 if (allowMouseControl)
1047 {
1048 exceptionContext = @"mouse control";
1049 if (!onTextEntryScreen && ([self checkKeyPress:n_key_mouse_control_roll] || [self checkKeyPress:n_key_mouse_control_yaw])) // 'M' key
1050 {
1051 if (!m_key_pressed)
1052 {
1053 mouse_control_on = !mouse_control_on;
1054 if (mouse_control_on)
1055 {
1056 [UNIVERSE addMessage:DESC(@"mouse-on") forCount:3.0];
1057 /* Ensure the keyboard pitch override (intended to lock
1058 out the joystick if the player runs to the keyboard)
1059 is reset */
1060 #if OOLITE_GNUSTEP
1061 [gameView resetMouse];
1062 if ([[NSUserDefaults standardUserDefaults] boolForKey:@"grab-mouse-on-mouse-control"])
1063 {
1064 [gameView grabMouseInsideGameWindow:YES];
1065 }
1066 #endif
1067 mouse_x_axis_map_to_yaw = [self checkKeyPress:n_key_mouse_control_yaw];
1068 keyboardRollOverride = mouse_x_axis_map_to_yaw; // Getafix: set keyboardRollOverride to TRUE only if yaw is mapped to mouse x-axis
1069 keyboardPitchOverride = NO;
1070 keyboardYawOverride = !keyboardRollOverride;
1071 }
1072 else
1073 {
1074 [UNIVERSE addMessage:DESC(@"mouse-off") forCount:3.0];
1075 #if OOLITE_GNUSTEP
1076 [gameView grabMouseInsideGameWindow:NO];
1077 #endif
1078 }
1079 }
1080 if (OOMouseInteractionModeIsFlightMode([gameController mouseInteractionMode]))
1081 {
1082 [gameController setMouseInteractionModeForFlight];
1083 }
1084 m_key_pressed = YES;
1085 }
1086 else
1087 {
1088 m_key_pressed = NO;
1089 }
1090 }
1091 else
1092 {
1093 if (mouse_control_on)
1094 {
1095 mouse_control_on = NO;
1096 [UNIVERSE addMessage:DESC(@"mouse-off") forCount:3.0];
1097 #if OOLITE_GNUSTEP
1098 [gameView grabMouseInsideGameWindow:NO];
1099 #endif
1100
1101 if (OOMouseInteractionModeIsFlightMode([gameController mouseInteractionMode]))
1102 {
1103 [gameController setMouseInteractionModeForFlight];
1104 }
1105 }
1106 }
1107
1108 // HUD toggle
1109 if (([self checkKeyPress:n_key_hud_toggle] || joyButtonState[BUTTON_TOGGLEHUD]) && [gameController isGamePaused] && !onTextEntryScreen) // 'o' key while paused
1110 {
1111 exceptionContext = @"toggle HUD";
1112 if (!hide_hud_pressed)
1113 {
1114 HeadUpDisplay *theHUD = [self hud];
1115 [theHUD setHidden:![theHUD isHidden]];
1116 if (gui_screen == GUI_SCREEN_STATUS)
1117 {
1118 // ensure refresh of status page screen if looking at it
1119 [self setGuiToStatusScreen];
1120 }
1121 }
1122 hide_hud_pressed = YES;
1123 }
1124 else
1125 {
1126 hide_hud_pressed = NO;
1127 }
1128 }
1129 @catch (NSException *exception)
1130 {
1131 OOLog(kOOLogException, @"***** Exception in pollApplicationControls [%@]: %@ : %@", exceptionContext, [exception name], [exception reason]);
1132 }
1133}
1134
1135
1136- (void) pollFlightControls:(double)delta_t
1137{
1138 MyOpenGLView *gameView = [UNIVERSE gameView];
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
3143- (void) pollMarketScreenControls
3144{
3145 MyOpenGLView *gameView = [UNIVERSE gameView];
3146 GuiDisplayGen *gui = [UNIVERSE gui];
3147
3148 if (gui_screen == GUI_SCREEN_MARKET)
3149 {
3150 [self handleGUIUpDownArrowKeys];
3151 DESTROY(marketSelectedCommodity);
3152 marketSelectedCommodity = [[gui selectedRowKey] retain];
3153
3154 BOOL page_up = [self checkKeyPress:n_key_gui_page_up];
3155 BOOL page_down = [self checkKeyPress:n_key_gui_page_down];
3156 if (page_up || page_down)
3157 {
3158 if ((!pageUpDownKeyPressed) || (script_time > timeLastKeyPress + KEY_REPEAT_INTERVAL))
3159 {
3160 OOCommodityMarket *localMarket = [self localMarket];
3161 NSArray *goods = [self applyMarketSorter:[self applyMarketFilter:[localMarket goods] onMarket:localMarket] onMarket:localMarket];
3162 if ([goods count] > 0)
3163 {
3164 NSInteger goodsIndex = [goods indexOfObject:marketSelectedCommodity];
3165 NSInteger offset1 = 0;
3166 NSInteger offset2 = 0;
3167 if ([[gui keyForRow:GUI_ROW_MARKET_START] isEqualToString:@"<<<"] == true) offset1 += 1;
3168 if ([[gui keyForRow:GUI_ROW_MARKET_LAST] isEqualToString:@">>>"] == true) offset2 += 1;
3169 if (page_up)
3170 {
3171 [self playMenuPagePrevious];
3172 // some edge cases
3173 if (goodsIndex - 16 <= 0)
3174 {
3175 offset1 = 0;
3176 offset2 = 0;
3177 }
3178 if (offset1 == 1 && offset2 == 0 && goodsIndex < (NSInteger)[goods count] - 1 && goodsIndex - 15 > 0) offset2 = 1;
3179 goodsIndex -= (16 - (offset1 + offset2));
3180 if (goodsIndex < 0) goodsIndex = 0;
3181 if ([goods count] <= 17) goodsIndex = 0;
3182 }
3183 if (page_down)
3184 {
3185 [self playMenuPageNext];
3186 // some edge cases
3187 if (offset1 == 0 && offset2 == 1 && goodsIndex > 1) offset1 = 1;
3188 if (offset2 == 1 && goodsIndex + 15 == (NSInteger)[goods count] - 1) offset2 = 0;
3189 goodsIndex += (16 - (offset1 + offset2));
3190 if (goodsIndex > ((NSInteger)[goods count] - 1) || [goods count] <= 17) goodsIndex = (NSInteger)[goods count] - 1;
3191 }
3192 DESTROY(marketSelectedCommodity);
3193 marketSelectedCommodity = [[goods oo_stringAtIndex:goodsIndex] retain];
3194 [self setGuiToMarketScreen];
3195 }
3196 }
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
3400- (void) handleGameOptionsScreenKeys
3401{
3402 MyOpenGLView *gameView = [UNIVERSE gameView];
3403 GuiDisplayGen *gui = [UNIVERSE gui];
3404 GUI_ROW_INIT(gui);
3405
3406 [self handleGUIUpDownArrowKeys];
3407 OOGUIRow guiSelectedRow = [gui selectedRow];
3408 BOOL selectKeyPress = ([self checkKeyPress:n_key_gui_select]||[gameView isDown:gvMouseDoubleClick]);
3409 if ([gameView isDown:gvMouseDoubleClick]) [gameView clearMouse];
3410
3411 if ((guiSelectedRow == GUI_ROW(GAME,STICKMAPPER)) && selectKeyPress)
3412 {
3413 selFunctionIdx = 0;
3414 [self resetStickFunctions]; // reset the list of stick functions, so changes in oxp equipment are reflected
3415 [self setGuiToStickMapperScreen: 0 resetCurrentRow: YES];
3416 }
3417 if ((guiSelectedRow == GUI_ROW(GAME,KEYMAPPER)) && selectKeyPress)
3418 {
3419 selFunctionIdx = 0;
3420 [self resetKeyFunctions]; // reset the list of key functions, so changes in oxp equipment are reflected
3421 [self setGuiToKeyMapperScreen: 0 resetCurrentRow: YES];
3422 }
3423
3424
3425#if OOLITE_WINDOWS
3426 if ([gameView hdrOutput])
3427 {
3428 if ((guiSelectedRow == GUI_ROW(GAME,HDRMAXBRIGHTNESS))&&(([self checkKeyPress:n_key_gui_arrow_right])||([self checkKeyPress:n_key_gui_arrow_left])))
3429 {
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 [gameView setHDRMaxBrightness:(float)brightnessValue];
3451 NSString *maxBrightnessString = OOExpandKey(@"gameoptions-hdr-maxbrightness", brightnessValue);
3452
3453 [gui setText:maxBrightnessString forRow:GUI_ROW(GAME,HDRMAXBRIGHTNESS) align:GUI_ALIGN_CENTER];
3454
3456 }
3457 }
3458 else
3460 }
3461#endif
3462
3463
3464#if OO_RESOLUTION_OPTION
3465 if (!switching_resolution &&
3466 guiSelectedRow == GUI_ROW(GAME,DISPLAY) &&
3467 ([self checkKeyPress:n_key_gui_arrow_right] || [self checkKeyPress:n_key_gui_arrow_left]))
3468 {
3469 GameController *controller = [UNIVERSE gameController];
3470 int direction = ([self checkKeyPress:n_key_gui_arrow_right]) ? 1 : -1;
3471 NSInteger displayModeIndex = [controller indexOfCurrentDisplayMode];
3472 NSArray *modes = [controller displayModes];
3473
3474 if (displayModeIndex == (NSInteger)NSNotFound)
3475 {
3476 OOLogWARN(@"graphics.mode.notFound", @"%@", @"couldn't find current fullscreen setting, switching to default.");
3477 displayModeIndex = 0;
3478 }
3479
3480 displayModeIndex = displayModeIndex + direction;
3481 int count = [modes count];
3482 if (displayModeIndex < 0)
3483 displayModeIndex = count - 1;
3484 if (displayModeIndex >= count)
3485 displayModeIndex = 0;
3486
3487 NSDictionary *mode = [modes objectAtIndex:displayModeIndex];
3488 int modeWidth = [mode oo_intForKey:kOODisplayWidth];
3489 int modeHeight = [mode oo_intForKey:kOODisplayHeight];
3490 int modeRefresh = [mode oo_intForKey:kOODisplayRefreshRate];
3491 [controller setDisplayWidth:modeWidth Height:modeHeight Refresh:modeRefresh];
3492
3493 NSString *displayModeString = [self screenModeStringForWidth:modeWidth height:modeHeight refreshRate:modeRefresh];
3494
3495 [self playChangedOption];
3496 [gui setText:displayModeString forRow:GUI_ROW(GAME,DISPLAY) align:GUI_ALIGN_CENTER];
3498
3499#if OOLITE_SDL
3500 /* TODO: The gameView for the SDL game currently holds and
3501 sets the actual screen resolution (controller just stores
3502 it). This probably ought to change. */
3503 [gameView setScreenSize: displayModeIndex]; // changes fullscreen mode immediately
3504#endif
3505 }
3506 if (switching_resolution && ![self checkKeyPress:n_key_gui_arrow_right] && ![self checkKeyPress:n_key_gui_arrow_left] && !selectKeyPress)
3507 {
3509 }
3510#endif // OO_RESOLUTION_OPTION
3511
3512#if OOLITE_SPEECH_SYNTH
3513
3514 if ((guiSelectedRow == GUI_ROW(GAME,SPEECH))&&(([self checkKeyPress:n_key_gui_arrow_right])||([self checkKeyPress:n_key_gui_arrow_left])))
3515 {
3516 if (!speech_settings_pressed)
3517 {
3518 if ([self checkKeyPress:n_key_gui_arrow_right] && isSpeechOn < OOSPEECHSETTINGS_ALL)
3519 {
3520 ++isSpeechOn;
3521 [self playChangedOption];
3522 speech_settings_pressed = YES;
3523 }
3524 else if ([self checkKeyPress:n_key_gui_arrow_left] && isSpeechOn > OOSPEECHSETTINGS_OFF)
3525 {
3526 speech_settings_pressed = YES;
3527 --isSpeechOn;
3528 [self playChangedOption];
3529 }
3530 if (speech_settings_pressed)
3531 {
3532 NSString *message = nil;
3533 switch (isSpeechOn)
3534 {
3536 message = DESC(@"gameoptions-spoken-messages-no");
3537 break;
3539 message = DESC(@"gameoptions-spoken-messages-comms");
3540 break;
3542 message = DESC(@"gameoptions-spoken-messages-yes");
3543 break;
3544 }
3545 [gui setText:message forRow:GUI_ROW(GAME,SPEECH) align:GUI_ALIGN_CENTER];
3546
3547 if (isSpeechOn == OOSPEECHSETTINGS_ALL)
3548 {
3549 [UNIVERSE stopSpeaking];
3550 [UNIVERSE startSpeakingString:message];
3551 }
3552 }
3553 }
3554 }
3555 else
3556 {
3557 speech_settings_pressed = NO;
3558 }
3559#if OOLITE_ESPEAK
3560 if (guiSelectedRow == GUI_ROW(GAME,SPEECH_LANGUAGE))
3561 {
3562 if ([self checkKeyPress:n_key_gui_arrow_right] || [self checkKeyPress:n_key_gui_arrow_left])
3563 {
3564 if (!speechVoiceSelectKeyPressed || script_time > timeLastKeyPress + KEY_REPEAT_INTERVAL)
3565 {
3566 [self playChangedOption];
3567 if ([self checkKeyPress:n_key_gui_arrow_right])
3568 voice_no = [UNIVERSE nextVoice: voice_no];
3569 else
3570 voice_no = [UNIVERSE prevVoice: voice_no];
3571 [UNIVERSE setVoice: voice_no withGenderM:voice_gender_m];
3572 NSString *voiceName = [UNIVERSE voiceName:voice_no];
3573 NSString *message = OOExpandKey(@"gameoptions-voice-name", voiceName);
3574 [gui setText:message forRow:GUI_ROW(GAME,SPEECH_LANGUAGE) align:GUI_ALIGN_CENTER];
3575 if (isSpeechOn == OOSPEECHSETTINGS_ALL)
3576 {
3577 [UNIVERSE stopSpeaking];
3578 [UNIVERSE startSpeakingString:[UNIVERSE voiceName: voice_no]];
3579 }
3580 timeLastKeyPress = script_time;
3581 }
3582 speechVoiceSelectKeyPressed = YES;
3583 }
3584 else
3585 speechVoiceSelectKeyPressed = NO;
3586 }
3587
3588 if (guiSelectedRow == GUI_ROW(GAME,SPEECH_GENDER))
3589 {
3590 if ([self checkKeyPress:n_key_gui_arrow_right] || [self checkKeyPress:n_key_gui_arrow_left])
3591 {
3592 if (!speechGenderSelectKeyPressed)
3593 {
3594 [self playChangedOption];
3595 BOOL m = [self checkKeyPress:n_key_gui_arrow_right];
3596 if (m != voice_gender_m)
3597 {
3598 voice_gender_m = m;
3599 [UNIVERSE setVoice:voice_no withGenderM:voice_gender_m];
3600 NSString *message = [NSString stringWithFormat:DESC(voice_gender_m ? @"gameoptions-voice-M" : @"gameoptions-voice-F")];
3601 [gui setText:message forRow:GUI_ROW(GAME,SPEECH_GENDER) align:GUI_ALIGN_CENTER];
3602 if (isSpeechOn == OOSPEECHSETTINGS_ALL)
3603 {
3604 [UNIVERSE stopSpeaking];
3605 [UNIVERSE startSpeakingString:[UNIVERSE voiceName: voice_no]];
3606 }
3607 }
3608 }
3609 speechGenderSelectKeyPressed = YES;
3610 }
3611 else
3612 speechGenderSelectKeyPressed = NO;
3613 }
3614#endif
3615#endif
3616
3617 if ((guiSelectedRow == GUI_ROW(GAME,MUSIC))&&(([self checkKeyPress:n_key_gui_arrow_right])||([self checkKeyPress:n_key_gui_arrow_left])))
3618 {
3620 {
3622 int initialMode = [musicController mode];
3623 int mode = initialMode;
3624
3625 if ([self checkKeyPress:n_key_gui_arrow_right]) mode++;
3626 if ([self checkKeyPress:n_key_gui_arrow_left]) mode--;
3627
3628 [musicController setMode:MAX(mode, 0)];
3629
3630 if ((int)[musicController mode] != initialMode)
3631 {
3632 [self playChangedOption];
3633 NSString *musicMode = [UNIVERSE descriptionForArrayKey:@"music-mode" index:[[OOMusicController sharedController] mode]];
3634 NSString *message = OOExpandKey(@"gameoptions-music-mode", musicMode);
3635 [gui setText:message forRow:GUI_ROW(GAME,MUSIC) align:GUI_ALIGN_CENTER];
3636 }
3637 }
3638 musicModeKeyPressed = YES;
3639 }
3640 else musicModeKeyPressed = NO;
3641
3642 if ((guiSelectedRow == GUI_ROW(GAME,AUTOSAVE))&&(([self checkKeyPress:n_key_gui_arrow_right])||([self checkKeyPress:n_key_gui_arrow_left])))
3643 {
3644 if ([self checkKeyPress:n_key_gui_arrow_right] != [UNIVERSE autoSave])
3645 [self playChangedOption];
3646 [UNIVERSE setAutoSave:[self checkKeyPress:n_key_gui_arrow_right]];
3647 if ([UNIVERSE autoSave])
3648 {
3649 // if just enabled, we want to autosave immediately
3650 [UNIVERSE setAutoSaveNow:YES];
3651 [gui setText:DESC(@"gameoptions-autosave-yes") forRow:GUI_ROW(GAME,AUTOSAVE) align:GUI_ALIGN_CENTER];
3652 }
3653 else
3654 {
3655 [UNIVERSE setAutoSaveNow:NO];
3656 [gui setText:DESC(@"gameoptions-autosave-no") forRow:GUI_ROW(GAME,AUTOSAVE) align:GUI_ALIGN_CENTER];
3657 }
3658 }
3659
3660 if ((guiSelectedRow == GUI_ROW(GAME,VOLUME))
3661 &&(([self checkKeyPress:n_key_gui_arrow_right])||([self checkKeyPress:n_key_gui_arrow_left]))
3662 &&[OOSound respondsToSelector:@selector(masterVolume)])
3663 {
3665 {
3666 BOOL rightKeyDown = [self checkKeyPress:n_key_gui_arrow_right];
3667 BOOL leftKeyDown = [self checkKeyPress:n_key_gui_arrow_left];
3668 double volume = 100.0 * [OOSound masterVolume];
3669 int vol = (volume / 5.0 + 0.5);
3670 if (rightKeyDown) vol++;
3671 if (leftKeyDown) vol--;
3672 vol = (int)OOClampInteger(vol, 0, 20);
3673 [OOSound setMasterVolume: 0.05 * vol];
3674 [self playChangedOption];
3675#if OOLITE_ESPEAK
3676 espeak_SetParameter(espeakVOLUME, vol * 5, 0);
3677#endif
3678 if (vol > 0)
3679 {
3680 NSString* soundVolumeWordDesc = DESC(@"gameoptions-sound-volume");
3681 NSString* v1_string = @"|||||||||||||||||||||||||";
3682 NSString* v0_string = @".........................";
3683 v1_string = [v1_string substringToIndex:vol];
3684 v0_string = [v0_string substringToIndex:20 - vol];
3685 [gui setText:[NSString stringWithFormat:@"%@%@%@ ", soundVolumeWordDesc, v1_string, v0_string]
3686 forRow:GUI_ROW(GAME,VOLUME)
3687 align:GUI_ALIGN_CENTER];
3688 }
3689 else
3690 [gui setText:DESC(@"gameoptions-sound-volume-mute") forRow:GUI_ROW(GAME,VOLUME) align:GUI_ALIGN_CENTER];
3691 timeLastKeyPress = script_time;
3692 }
3694 }
3695 else
3697
3698#if OOLITE_SDL
3699 if ((guiSelectedRow == GUI_ROW(GAME,GAMMA))
3700 &&(([self checkKeyPress:n_key_gui_arrow_right])||([self checkKeyPress:n_key_gui_arrow_left])))
3701 {
3702 if (!gammaControlPressed)
3703 {
3704 BOOL rightKeyDown = [self checkKeyPress:n_key_gui_arrow_right];
3705 BOOL leftKeyDown = [self checkKeyPress:n_key_gui_arrow_left];
3706 float gamma = [gameView gammaValue];
3707 gamma += (((rightKeyDown && (gamma < 4.0f)) ? 0.2f : 0.0f) - ((leftKeyDown && (gamma > 0.2f)) ? 0.2f : 0.0f));
3708 if (gamma > 3.95f) gamma = 4.0f;
3709 if (gamma < 0.25f) gamma = 0.2f;
3710 [gameView setGammaValue:gamma];
3711 int gamma5 = gamma * 5; // avoid rounding errors
3712 NSString* gammaWordDesc = DESC(@"gameoptions-gamma-value");
3713 NSString* v1_string = @"|||||||||||||||||||||||||";
3714 NSString* v0_string = @".........................";
3715 v1_string = [v1_string substringToIndex:gamma5];
3716 v0_string = [v0_string substringToIndex:20 - gamma5];
3717 [gui setText:[NSString stringWithFormat:@"%@%@%@ (%.1f) ", gammaWordDesc, v1_string, v0_string, gamma] forRow:GUI_ROW(GAME,GAMMA) align:GUI_ALIGN_CENTER];
3718 }
3719 gammaControlPressed = YES;
3720 }
3721 else
3722 gammaControlPressed = NO;
3723#endif
3724
3725
3726 if ((guiSelectedRow == GUI_ROW(GAME,FOV))
3727 &&(([self checkKeyPress:n_key_gui_arrow_right])||([self checkKeyPress:n_key_gui_arrow_left])))
3728 {
3730 {
3731 BOOL rightKeyDown = [self checkKeyPress:n_key_gui_arrow_right];
3732 BOOL leftKeyDown = [self checkKeyPress:n_key_gui_arrow_left];
3733 float fov = [gameView fov:NO];
3734 float fovStep = (MAX_FOV_DEG - MIN_FOV_DEG) / 20.0f;
3735 fov += (((rightKeyDown && (fov < MAX_FOV_DEG)) ?
3736 fovStep : 0.0f) - ((leftKeyDown && (fov > MIN_FOV_DEG)) ? fovStep : 0.0f));
3737 if (fov > MAX_FOV_DEG) fov = MAX_FOV_DEG;
3738 if (fov < MIN_FOV_DEG) fov = MIN_FOV_DEG;
3739 [gameView setFov:fov fromFraction:NO];
3740 fieldOfView = [gameView fov:YES];
3741 int fovTicks = (int)((fov - MIN_FOV_DEG) / fovStep);
3742 NSString* fovWordDesc = DESC(@"gameoptions-fov-value");
3743 NSString* v1_string = @"|||||||||||||||||||||||||";
3744 NSString* v0_string = @".........................";
3745 v1_string = [v1_string substringToIndex:fovTicks];
3746 v0_string = [v0_string substringToIndex:20 - fovTicks];
3747 [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];
3748 [[NSUserDefaults standardUserDefaults] setFloat:[gameView fov:NO] forKey:@"fov-value"];
3749 timeLastKeyPress = script_time;
3750 }
3751 fovControlPressed = YES;
3752 }
3753 else
3754 fovControlPressed = NO;
3755
3756
3757 // color blind mode
3758 if ((guiSelectedRow == GUI_ROW(GAME,COLORBLINDMODE))&&(([self checkKeyPress:n_key_gui_arrow_right])||([self checkKeyPress:n_key_gui_arrow_left])))
3759 {
3761 {
3762 int colorblindMode = [UNIVERSE colorblindMode];
3763 if ([self checkKeyPress:n_key_gui_arrow_right])
3764 {
3765 [UNIVERSE setCurrentPostFX:[UNIVERSE nextColorblindMode:colorblindMode]];
3766 }
3767 else
3768 {
3769 [UNIVERSE setCurrentPostFX:[UNIVERSE prevColorblindMode:colorblindMode]];
3770 }
3771 colorblindMode = [UNIVERSE colorblindMode]; // get the updated value
3772 NSString *colorblindModeDesc = [[[UNIVERSE descriptions] oo_arrayForKey: @"colorblind_mode"] oo_stringAtIndex:[UNIVERSE useShaders] ? colorblindMode : 0];
3773 NSString *colorblindModeMsg = OOExpandKey(@"gameoptions-colorblind-mode", colorblindModeDesc);
3774 [gui setText:colorblindModeMsg forRow:GUI_ROW(GAME,COLORBLINDMODE) align:GUI_ALIGN_CENTER];
3775 }
3777 }
3778 else
3780
3781
3782 if (![gameView hdrOutput])
3783 {
3784 if ((guiSelectedRow == GUI_ROW(GAME,WIREFRAMEGRAPHICS))&&(([self checkKeyPress:n_key_gui_arrow_right])||([self checkKeyPress:n_key_gui_arrow_left])))
3785 {
3786 if ([self checkKeyPress:n_key_gui_arrow_right] != [UNIVERSE wireframeGraphics])
3787 [self playChangedOption];
3788 [UNIVERSE setWireframeGraphics:[self checkKeyPress:n_key_gui_arrow_right]];
3789 if ([UNIVERSE wireframeGraphics])
3790 [gui setText:DESC(@"gameoptions-wireframe-graphics-yes") forRow:GUI_ROW(GAME,WIREFRAMEGRAPHICS) align:GUI_ALIGN_CENTER];
3791 else
3792 [gui setText:DESC(@"gameoptions-wireframe-graphics-no") forRow:GUI_ROW(GAME,WIREFRAMEGRAPHICS) align:GUI_ALIGN_CENTER];
3793 }
3794 }
3795#if OOLITE_WINDOWS
3796 else
3797 {
3798 if ((guiSelectedRow == GUI_ROW(GAME,HDRPAPERWHITE))
3799 &&(([self checkKeyPress:n_key_gui_arrow_right])||([self checkKeyPress:n_key_gui_arrow_left])))
3800 {
3802 {
3803 BOOL rightKeyDown = [self checkKeyPress:n_key_gui_arrow_right];
3804 BOOL leftKeyDown = [self checkKeyPress:n_key_gui_arrow_left];
3805 float paperWhite = [gameView hdrPaperWhiteBrightness];
3806 paperWhite += (((rightKeyDown && (paperWhite < MAX_HDR_PAPERWHITE)) ? 10.0f : 0.0f) - ((leftKeyDown && (paperWhite > MIN_HDR_PAPERWHITE)) ? 10.0f : 0.0f));
3807 if (paperWhite > MAX_HDR_PAPERWHITE) paperWhite = MAX_HDR_PAPERWHITE;
3808 if (paperWhite < MIN_HDR_PAPERWHITE) paperWhite = MIN_HDR_PAPERWHITE;
3809 [gameView setHDRPaperWhiteBrightness:paperWhite];
3810 int paperWhiteNorm = (int)((paperWhite - MIN_HDR_PAPERWHITE) * 20 / (MAX_HDR_PAPERWHITE - MIN_HDR_PAPERWHITE));
3811 NSString* paperWhiteWordDesc = DESC(@"gameoptions-hdr-paperwhite");
3812 NSString* v1_string = @"|||||||||||||||||||||||||";
3813 NSString* v0_string = @".........................";
3814 v1_string = [v1_string substringToIndex:paperWhiteNorm];
3815 v0_string = [v0_string substringToIndex:20 - paperWhiteNorm];
3816 [gui setText:[NSString stringWithFormat:@"%@%@%@ (%d) ", paperWhiteWordDesc, v1_string, v0_string, (int)paperWhite] forRow:GUI_ROW(GAME,HDRPAPERWHITE) align:GUI_ALIGN_CENTER];
3817 }
3819 }
3820 else
3822 }
3823#endif
3824
3825#if !NEW_PLANETS
3826 if ((guiSelectedRow == GUI_ROW(GAME,PROCEDURALLYTEXTUREDPLANETS))&&(([self checkKeyPress:n_key_gui_arrow_right])||([self checkKeyPress:n_key_gui_arrow_left])))
3827 {
3828 if ([self checkKeyPress:n_key_gui_arrow_right] != [UNIVERSE doProcedurallyTexturedPlanets])
3829 {
3830 [UNIVERSE setDoProcedurallyTexturedPlanets:[self checkKeyPress:n_key_gui_arrow_right]];
3831 [self playChangedOption];
3832 if ([UNIVERSE planet])
3833 {
3834 [UNIVERSE setUpPlanet];
3835 }
3836 }
3837 if ([UNIVERSE doProcedurallyTexturedPlanets])
3838 [gui setText:DESC(@"gameoptions-procedurally-textured-planets-yes") forRow:GUI_ROW(GAME,PROCEDURALLYTEXTUREDPLANETS) align:GUI_ALIGN_CENTER];
3839 else
3840 [gui setText:DESC(@"gameoptions-procedurally-textured-planets-no") forRow:GUI_ROW(GAME,PROCEDURALLYTEXTUREDPLANETS) align:GUI_ALIGN_CENTER];
3841 }
3842#endif
3843
3844 if (guiSelectedRow == GUI_ROW(GAME,SHADEREFFECTS) && ([self checkKeyPress:n_key_gui_arrow_right] || [self checkKeyPress:n_key_gui_arrow_left]))
3845 {
3847 {
3848 int direction = ([self checkKeyPress:n_key_gui_arrow_right]) ? 1 : -1;
3849
3850 /* (Getafix - 2015/05/07)
3851 Fix bug coincidentally resulting in Graphics Detail value cycling
3852 when left arrow is pressed.
3853
3854 OOGraphicsDetail is an enum type and as such it will never go
3855 negative. The following code adjusts "direction" to avoid illegal
3856 detailLevel values.
3857
3858 Perhaps a more elegant solution could be set in place, restructuring
3859 in Universe.m the logic behing setDetailLevelDirectly and
3860 setDetailLevel, not forgetting to consider Graphic Detail assigned
3861 from various sources (i.e. menu, user prefs file, javascript, etc.).
3862 This is postponed in order not to risk the recently announced
3863 plans for v1.82 release.
3864
3865 Generally we should decide whether the menu values should cycle or
3866 not and apply it for all menu entries.
3867 */
3868 if ((([UNIVERSE detailLevel] == DETAIL_LEVEL_MINIMUM) && (direction == -1)) ||
3869 (([UNIVERSE detailLevel] == DETAIL_LEVEL_MAXIMUM) && (direction == 1)))
3870 direction = 0;
3871
3872 OOGraphicsDetail detailLevel = [UNIVERSE detailLevel] + direction;
3873 [UNIVERSE setDetailLevel:detailLevel];
3874 detailLevel = [UNIVERSE detailLevel];
3875
3876 NSString *shaderEffectsOptionsString = OOExpand(@"gameoptions-detaillevel-[detailLevel]", detailLevel);
3877 [gui setText:OOExpandKey(shaderEffectsOptionsString) forRow:GUI_ROW(GAME,SHADEREFFECTS) align:GUI_ALIGN_CENTER];
3878 [gui setKey:GUI_KEY_OK forRow:GUI_ROW(GAME,SHADEREFFECTS)];
3879
3880 timeLastKeyPress = script_time;
3881
3882 // changing detail level may result in changes to other settings too
3883 // (e.g. colorblind mode status), so refresh the page
3884 [self setGuiToGameOptionsScreen];
3885 [gui setSelectedRow:GUI_ROW(GAME,SHADEREFFECTS)];
3886 }
3888 }
3889 else shaderSelectKeyPressed = NO;
3890
3891#if OOLITE_SDL
3892 if ((guiSelectedRow == GUI_ROW(GAME,DISPLAYSTYLE)) && selectKeyPress)
3893 {
3894 [gameView toggleScreenMode];
3895 // redraw GUI
3896 [self setGuiToGameOptionsScreen];
3897 }
3898#endif
3899
3900 if ((guiSelectedRow == GUI_ROW(GAME,DOCKINGCLEARANCE))&&(([self checkKeyPress:n_key_gui_arrow_right])||([self checkKeyPress:n_key_gui_arrow_left])))
3901 {
3902 if ([self checkKeyPress:n_key_gui_arrow_right] != [UNIVERSE dockingClearanceProtocolActive])
3903 [self playChangedOption];
3904 [UNIVERSE setDockingClearanceProtocolActive:[self checkKeyPress:n_key_gui_arrow_right]];
3905 if ([UNIVERSE dockingClearanceProtocolActive])
3906 [gui setText:DESC(@"gameoptions-docking-clearance-yes") forRow:GUI_ROW(GAME,DOCKINGCLEARANCE) align:GUI_ALIGN_CENTER];
3907 else
3908 [gui setText:DESC(@"gameoptions-docking-clearance-no") forRow:GUI_ROW(GAME,DOCKINGCLEARANCE) align:GUI_ALIGN_CENTER];
3909 }
3910
3911 if ((guiSelectedRow == GUI_ROW(GAME,BACK)) && selectKeyPress)
3912 {
3913 [gameView clearKeys];
3914 [self setGuiToLoadSaveScreen];
3915 }
3916}
3917
3918
3919- (void) handleKeyMapperScreenKeys
3920{
3921 MyOpenGLView *gameView = [UNIVERSE gameView];
3922 GuiDisplayGen *gui = [UNIVERSE gui];
3923
3924 [self keyMapperInputHandler: gui view: gameView];
3925 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];
3927 {
3928 NSString *key = [gui keyForRow: [gui selectedRow]];
3929 if ([self checkKeyPress:n_key_gui_arrow_right] || [self checkKeyPress:n_key_gui_page_down])
3930 {
3931 key = [gui keyForRow:GUI_ROW_KC_FUNCEND];
3932 }
3933 if ([self checkKeyPress:n_key_gui_arrow_left] || [self checkKeyPress:n_key_gui_page_up])
3934 {
3935 key = [gui keyForRow:GUI_ROW_KC_FUNCSTART];
3936 }
3937 int from_function = 0;
3938 NSArray *keyComponents = [key componentsSeparatedByString:@":"];
3939 if ([keyComponents count] > 1)
3940 {
3941 from_function = [keyComponents oo_intAtIndex:1];
3942 if (from_function < 0) from_function = 0;
3943
3944 [self setGuiToKeyMapperScreen:from_function resetCurrentRow: YES];
3945 if ([[UNIVERSE gui] selectedRow] < GUI_ROW_KC_FUNCSTART)
3946 {
3947 [[UNIVERSE gui] setSelectedRow: GUI_ROW_KC_FUNCSTART];
3948 }
3949 if (from_function == 0)
3950 {
3951 [[UNIVERSE gui] setSelectedRow: GUI_ROW_KC_FUNCSTART + MAX_ROWS_KC_FUNCTIONS - 1];
3952 }
3953 }
3954 }
3955}
3956
3957
3958- (void) handleKeyboardLayoutKeys
3959{
3960 MyOpenGLView *gameView = [UNIVERSE gameView];
3961 GuiDisplayGen *gui = [UNIVERSE gui];
3962
3963 [self handleKeyboardLayoutEntryKeys: gui view: gameView];
3964 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];
3966 {
3967 NSString *key = [gui keyForRow: [gui selectedRow]];
3968 if ([self checkKeyPress:n_key_gui_arrow_right] || [self checkKeyPress:n_key_gui_page_down])
3969 {
3970 key = [gui keyForRow:GUI_ROW_KC_FUNCEND];
3971 }
3972 if ([self checkKeyPress:n_key_gui_arrow_left] || [self checkKeyPress:n_key_gui_page_up])
3973 {
3974 key = [gui keyForRow:GUI_ROW_KC_FUNCSTART];
3975 }
3976 int from_function = 0;
3977 NSArray *keyComponents = [key componentsSeparatedByString:@":"];
3978 if ([keyComponents count] > 1)
3979 {
3980 from_function = [keyComponents oo_intAtIndex:1];
3981 if (from_function < 0) from_function = 0;
3982
3983 [self setGuiToKeyboardLayoutScreen:from_function resetCurrentRow:YES];
3984 if ([[UNIVERSE gui] selectedRow] < GUI_ROW_KC_FUNCSTART)
3985 {
3986 [[UNIVERSE gui] setSelectedRow: GUI_ROW_KC_FUNCSTART];
3987 }
3988 if (from_function == 0)
3989 {
3990 [[UNIVERSE gui] setSelectedRow: GUI_ROW_KC_FUNCSTART + MAX_ROWS_KC_FUNCTIONS - 1];
3991 }
3992 }
3993 }
3994}
3995
3996
3997- (void) handleStickMapperScreenKeys
3998{
3999 MyOpenGLView *gameView = [UNIVERSE gameView];
4000 GuiDisplayGen *gui = [UNIVERSE gui];
4001
4002 [self stickMapperInputHandler: gui view: gameView];
4003 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];
4005 {
4006 NSString *key = [gui keyForRow: [gui selectedRow]];
4007 if ([self checkKeyPress:n_key_gui_arrow_right] || [self checkKeyPress:n_key_gui_page_down])
4008 {
4009 key = [gui keyForRow:GUI_ROW_FUNCEND];
4010 }
4011 if ([self checkKeyPress:n_key_gui_arrow_left] || [self checkKeyPress:n_key_gui_page_up])
4012 {
4013 key = [gui keyForRow:GUI_ROW_FUNCSTART];
4014 }
4015 int from_function = 0;
4016 NSArray *keyComponents = [key componentsSeparatedByString:@":"];
4017 if ([keyComponents count] > 1)
4018 {
4019 from_function = [keyComponents oo_intAtIndex:1];
4020 if (from_function < 0) from_function = 0;
4021
4022 [self setGuiToStickMapperScreen:from_function resetCurrentRow: YES];
4023 if ([[UNIVERSE gui] selectedRow] < GUI_ROW_FUNCSTART)
4024 {
4025 [[UNIVERSE gui] setSelectedRow: GUI_ROW_FUNCSTART];
4026 }
4027 if (from_function == 0)
4028 {
4029 [[UNIVERSE gui] setSelectedRow: GUI_ROW_FUNCSTART + MAX_ROWS_FUNCTIONS - 1];
4030 }
4031 }
4032 }
4033 if([gameView isDown:' ']) [self setGuiToGameOptionsScreen];
4034}
4035
4036
4037- (void) pollCustomViewControls
4038{
4039 static Quaternion viewQuaternion;
4040 static Vector viewOffset;
4041 static Vector rotationCenter;
4042 static Vector up;
4043 static Vector right;
4044 static BOOL mouse_clicked = NO;
4045 static NSPoint mouse_clicked_position;
4046 static BOOL shift_down;
4047 static BOOL caps_on = NO;
4048 static NSTimeInterval last_time = 0.0;
4049 MyOpenGLView *gameView = [UNIVERSE gameView];
4050 const BOOL *joyButtonState = [[OOJoystickManager sharedStickHandler] getAllButtonStates];
4051
4052 if ([self checkKeyPress:n_key_custom_view] || joyButtonState[BUTTON_EXTVIEWCYCLE])
4053 {
4054 if (!customView_pressed && [_customViews count] != 0 && gui_screen != GUI_SCREEN_LONG_RANGE_CHART && ![gameView allowingStringInput])
4055 {
4056 if ([UNIVERSE viewDirection] == VIEW_CUSTOM) // already in custom view mode
4057 {
4058 // rotate the custom views
4059 _customViewIndex = (_customViewIndex + 1) % [_customViews count];
4060 }
4061
4062 [self setCustomViewDataFromDictionary:[_customViews oo_dictionaryAtIndex:_customViewIndex] withScaling:YES];
4063
4064 [self switchToThisView:VIEW_CUSTOM andProcessWeaponFacing:NO]; // weapon facing must not change, we just want an external view
4065 }
4066 customView_pressed = YES;
4067 }
4068 else
4069 customView_pressed = NO;
4070 NSTimeInterval this_time = [NSDate timeIntervalSinceReferenceDate];
4071 if ([UNIVERSE viewDirection] > VIEW_STARBOARD && [gameView isCapsLockOn])
4072 {
4073 BOOL ctrl_down = [gameView isCtrlDown];
4074 float customViewZoomSpeed = ctrl_down ? CUSTOM_VIEW_ZOOM_SPEED * CUSTOM_VIEW_SPEED_REDUCTION_FACTOR: CUSTOM_VIEW_ZOOM_SPEED;
4076
4077 if (!caps_on) caps_on = YES;
4078
4079 OOTimeDelta delta_t = this_time - last_time;
4080 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)
4081 {
4082 [self customViewZoomOut: pow(customViewZoomSpeed, delta_t)];
4083 }
4084 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)
4085 {
4086 [self customViewZoomIn: pow(customViewZoomSpeed, delta_t)];
4087 }
4088 if ([self checkKeyPress:n_key_custom_view_roll_left ignore_ctrl:YES] && ![self checkKeyPress:n_key_custom_view_roll_right ignore_ctrl:YES])
4089 {
4090 [self customViewRollLeft:customViewRotateSpeed * delta_t];
4091 }
4092 if ([self checkKeyPress:n_key_custom_view_pan_left ignore_ctrl:YES] && ![self checkKeyPress:n_key_custom_view_pan_right ignore_ctrl:YES])
4093 {
4094 [self customViewPanLeft:customViewRotateSpeed * delta_t];
4095 }
4096 if ([self checkKeyPress:n_key_custom_view_roll_right ignore_ctrl:YES] && ![self checkKeyPress:n_key_custom_view_roll_left ignore_ctrl:YES])
4097 {
4098 [self customViewRollRight:customViewRotateSpeed * delta_t];
4099 }
4100 if ([self checkKeyPress:n_key_custom_view_pan_right ignore_ctrl:YES] && ![self checkKeyPress:n_key_custom_view_pan_left ignore_ctrl:YES])
4101 {
4102 [self customViewPanRight:customViewRotateSpeed * delta_t];
4103 }
4104 if ([self checkKeyPress:n_key_custom_view_rotate_up ignore_ctrl:YES] && ![self checkKeyPress:n_key_custom_view_rotate_down ignore_ctrl:YES])
4105 {
4106 [self customViewRotateUp:customViewRotateSpeed * delta_t];
4107 }
4108 if ([self checkKeyPress:n_key_custom_view_pan_down ignore_ctrl:YES] && ![self checkKeyPress:n_key_custom_view_pan_up ignore_ctrl:YES])
4109 {
4110 [self customViewPanDown:customViewRotateSpeed * delta_t];
4111 }
4112 if ([self checkKeyPress:n_key_custom_view_rotate_down ignore_ctrl:YES] && ![self checkKeyPress:n_key_custom_view_rotate_up ignore_ctrl:YES])
4113 {
4114 [self customViewRotateDown:customViewRotateSpeed * delta_t];
4115 }
4116 if ([self checkKeyPress:n_key_custom_view_pan_up ignore_ctrl:YES] && ![self checkKeyPress:n_key_custom_view_pan_down ignore_ctrl:YES])
4117 {
4118 [self customViewPanUp:customViewRotateSpeed * delta_t];
4119 }
4120 if ([self checkKeyPress:n_key_custom_view_rotate_left ignore_ctrl:YES] && ![self checkKeyPress:n_key_custom_view_rotate_right ignore_ctrl:YES])
4121 {
4122 [self customViewRotateLeft:customViewRotateSpeed * delta_t];
4123 }
4124 if ([self checkKeyPress:n_key_custom_view_rotate_right ignore_ctrl:YES] && ![self checkKeyPress:n_key_custom_view_rotate_left ignore_ctrl:YES])
4125 {
4126 [self customViewRotateRight:customViewRotateSpeed * delta_t];
4127 }
4128 if ([gameView isDown:gvMouseLeftButton])
4129 {
4130 if(!mouse_clicked || shift_down != [gameView isShiftDown])
4131 {
4132 mouse_clicked = YES;
4133 viewQuaternion = [PLAYER customViewQuaternion];
4134 viewOffset = [PLAYER customViewOffset];
4135 rotationCenter = [PLAYER customViewRotationCenter];
4136 up = [PLAYER customViewUpVector];
4137 right = [PLAYER customViewRightVector];
4138 mouse_clicked_position = [gameView virtualJoystickPosition];
4139 shift_down = [gameView isShiftDown];
4140 }
4141 NSPoint mouse_position = [gameView virtualJoystickPosition];
4142 Vector axis = vector_add(vector_multiply_scalar(up, mouse_position.x - mouse_clicked_position.x),
4143 vector_multiply_scalar(right, mouse_position.y - mouse_clicked_position.y));
4144 float angle = magnitude(axis);
4145 axis = vector_normal(axis);
4146 Quaternion newViewQuaternion = viewQuaternion;
4147 if ([gameView isShiftDown])
4148 {
4149 quaternion_rotate_about_axis(&newViewQuaternion, axis, angle);
4150 [PLAYER setCustomViewQuaternion: newViewQuaternion];
4151 [PLAYER setCustomViewRotationCenter: vector_subtract(viewOffset,
4152 vector_multiply_scalar([PLAYER customViewForwardVector],
4153 dot_product([PLAYER customViewForwardVector], viewOffset)))];
4154 }
4155 else
4156 {
4157 quaternion_rotate_about_axis(&newViewQuaternion, axis, -angle);
4158 OOScalar m = magnitude(vector_subtract(viewOffset, rotationCenter));
4159 [PLAYER setCustomViewQuaternion: newViewQuaternion];
4160 Vector offset = vector_flip([PLAYER customViewForwardVector]);
4161 scale_vector(&offset, m / magnitude(offset));
4162 [PLAYER setCustomViewOffset:vector_add(offset, rotationCenter)];
4163 }
4164 }
4165 else
4166 {
4167 mouse_clicked = NO;
4168 }
4169 }
4170 else
4171 {
4172 mouse_clicked = NO;
4173 if (caps_on)
4174 {
4175 caps_on = NO;
4176 if ([self isMouseControlOn]) [gameView resetMouse];
4177 }
4178 }
4179 last_time = this_time;
4180}
4181
4182
4183- (void) pollViewControls
4184{
4185 if(!pollControls)
4186 return;
4187
4188 MyOpenGLView *gameView = [UNIVERSE gameView];
4190
4191 NSPoint virtualView = NSZeroPoint;
4192 double view_threshold = 0.5;
4193
4194 if ([stickHandler joystickCount])
4195 {
4196 virtualView = [stickHandler viewAxis];
4197 if (virtualView.y == STICK_AXISUNASSIGNED)
4198 virtualView.y = 0.0;
4199 if (virtualView.x == STICK_AXISUNASSIGNED)
4200 virtualView.x = 0.0;
4201 if (fabs(virtualView.y) >= fabs(virtualView.x))
4202 virtualView.x = 0.0; // forward/aft takes precedence
4203 else
4204 virtualView.y = 0.0;
4205 }
4206
4207 const BOOL *joyButtonState = [stickHandler getAllButtonStates];
4208
4209 // view keys
4210 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]))
4211 {
4212 [self switchToThisView:VIEW_FORWARD];
4213 }
4214 if (([self checkKeyPress:n_key_view_aft])||(virtualView.y > view_threshold)||joyButtonState[BUTTON_VIEWAFT])
4215 {
4216 [self switchToThisView:VIEW_AFT];
4217 }
4218 if (([self checkKeyPress:n_key_view_port])||(virtualView.x < -view_threshold)||joyButtonState[BUTTON_VIEWPORT])
4219 {
4220 [self switchToThisView:VIEW_PORT];
4221 }
4222 if (([self checkKeyPress:n_key_view_starboard])||(virtualView.x > view_threshold)||joyButtonState[BUTTON_VIEWSTARBOARD])
4223 {
4224 [self switchToThisView:VIEW_STARBOARD];
4225 }
4226
4227 [self pollCustomViewControls];
4228
4229 // Zoom scanner 'z'
4230 if (([self checkKeyPress:n_key_scanner_zoom] && ([gameView allowingStringInput] == gvStringInputNo)) || joyButtonState[BUTTON_SCANNERZOOM]) // look for the 'z' key
4231 {
4232 if (!scanner_zoom_rate)
4233 {
4234 if ([hud scannerZoom] < 5.0)
4235 {
4236 if (([hud scannerZoom] > 1.0)||(!zoom_pressed))
4237 scanner_zoom_rate = SCANNER_ZOOM_RATE_UP;
4238 }
4239 else
4240 {
4241 if (!zoom_pressed) // must release and re-press zoom to zoom back down..
4242 scanner_zoom_rate = SCANNER_ZOOM_RATE_DOWN;
4243 }
4244 }
4245 zoom_pressed = YES;
4246 }
4247 else
4248 zoom_pressed = NO;
4249
4250 // Unzoom scanner 'Z'
4251 if (([self checkKeyPress:n_key_scanner_unzoom] && ([gameView allowingStringInput] == gvStringInputNo)) || joyButtonState[BUTTON_SCANNERUNZOOM]) // look for the 'Z' key
4252 {
4253 if ((!scanner_zoom_rate)&&([hud scannerZoom] > 1.0))
4254 scanner_zoom_rate = SCANNER_ZOOM_RATE_DOWN;
4255 }
4256
4257 if (EXPECT([[self hud] isCompassActive])) // only switch compass modes if there is a compass
4258 {
4259 // Compass mode '|'
4260 if ([self checkKeyPress:n_key_prev_compass_mode] || joyButtonState[BUTTON_COMPASSMODE_PREV]) // look for the '|' key
4261 {
4262 if ((!prev_compass_mode_pressed)&&(compassMode != COMPASS_MODE_BASIC))
4263 [self setPrevCompassMode];
4265 }
4266 else
4267 {
4269 }
4270 // Compass mode '\'
4271 if ([self checkKeyPress:n_key_next_compass_mode] || joyButtonState[BUTTON_COMPASSMODE]) // look for the '\' key
4272 {
4273 if ((!next_compass_mode_pressed)&&(compassMode != COMPASS_MODE_BASIC))
4274 [self setNextCompassMode];
4276 }
4277 else
4278 {
4280 }
4281 }
4282
4283 // ';' // Cycle active MFD
4284 if ([self checkKeyPress:n_key_cycle_next_mfd] || [self checkKeyPress:n_key_cycle_previous_mfd] || joyButtonState[BUTTON_MFDCYCLENEXT] || joyButtonState[BUTTON_MFDCYCLEPREV])
4285 {
4286 if (!cycleMFD_pressed)
4287 {
4288 //if (![gameView isCtrlDown])
4289 if (![self checkKeyPress:n_key_cycle_previous_mfd] || joyButtonState[BUTTON_MFDCYCLEPREV])
4290 {
4291 [self cycleNextMultiFunctionDisplay:activeMFD];
4292 }
4293 else
4294 {
4295 [self cyclePreviousMultiFunctionDisplay:activeMFD];
4296 }
4297 }
4298 cycleMFD_pressed = YES;
4299 }
4300 else
4301 {
4302 cycleMFD_pressed = NO;
4303 }
4304
4305 // ':' // Select next MFD
4306 if ([self checkKeyPress:n_key_switch_next_mfd] || [self checkKeyPress:n_key_switch_previous_mfd] || joyButtonState[BUTTON_MFDSELECTNEXT] || joyButtonState[BUTTON_MFDSELECTPREV])
4307 {
4308 if ([[self hud] mfdCount] > 1)
4309 {
4310 if (!switchMFD_pressed)
4311 {
4312 //if (![gameView isCtrlDown])
4313 if (![self checkKeyPress:n_key_switch_previous_mfd] || joyButtonState[BUTTON_MFDSELECTPREV])
4314 {
4315 [self selectNextMultiFunctionDisplay];
4316 }
4317 else
4318 {
4319 [self selectPreviousMultiFunctionDisplay];
4320 }
4321 }
4322 }
4323 switchMFD_pressed = YES;
4324 }
4325 else
4326 {
4327 switchMFD_pressed = NO;
4328 }
4329
4330
4331 // show comms log '`'
4332 if ([self checkKeyPress:n_key_comms_log])
4333 {
4334 [UNIVERSE showCommsLog: 1.5];
4335 [hud refreshLastTransmitter];
4336 }
4337}
4338
4339
4340- (void) pollFlightArrowKeyControls:(double)delta_t
4341{
4342 MyOpenGLView *gameView = [UNIVERSE gameView];
4344 NSUInteger numSticks = [stickHandler joystickCount];
4345 NSPoint virtualStick = NSZeroPoint;
4346 double reqYaw = 0.0;
4347
4348 /* DJS: Handle inputs on the joy roll/pitch axis.
4349 Mouse control on takes precedence over joysticks.
4350 We have to assume the player has a reason for switching mouse
4351 control on if they have a joystick - let them do it. */
4352 if (mouse_control_on)
4353 {
4354 virtualStick=[gameView virtualJoystickPosition];
4355 double sensitivity = 2.0;
4356 virtualStick.x *= sensitivity;
4357 virtualStick.y *= sensitivity;
4358 reqYaw = virtualStick.x;
4359 }
4360 else if (numSticks > 0)
4361 {
4362 virtualStick = [stickHandler rollPitchAxis];
4363 // handle roll separately (fix for BUG #17490)
4364 if(virtualStick.x == STICK_AXISUNASSIGNED)
4365 {
4366 // Not assigned - set to zero.
4367 virtualStick.x=0;
4368 }
4369 else if(virtualStick.x != 0)
4370 {
4371 // cancel keyboard override, stick has been waggled
4372 keyboardRollOverride=NO;
4373 }
4374 // handle pitch separately (fix for BUG #17490)
4375 if(virtualStick.y == STICK_AXISUNASSIGNED)
4376 {
4377 // Not assigned - set to zero.
4378 virtualStick.y=0;
4379 }
4380 else if(virtualStick.y != 0)
4381 {
4382 // cancel keyboard override, stick has been waggled
4383 keyboardPitchOverride=NO;
4384 }
4385 // handle yaw separately from pitch/roll
4386 reqYaw = [stickHandler getAxisState: AXIS_YAW];
4387 if(reqYaw == STICK_AXISUNASSIGNED)
4388 {
4389 // Not assigned or deadzoned - set to zero.
4390 reqYaw=0;
4391 }
4392 else if(reqYaw != 0)
4393 {
4394 // cancel keyboard override, stick has been waggled
4395 keyboardYawOverride=NO;
4396 }
4397 }
4398
4399 double roll_dampner = ROLL_DAMPING_FACTOR * delta_t;
4400 double pitch_dampner = PITCH_DAMPING_FACTOR * delta_t;
4401 double yaw_dampner = YAW_DAMPING_FACTOR * delta_t;
4402 BOOL capsLockCustomView = [UNIVERSE viewDirection] == VIEW_CUSTOM && [gameView isCapsLockOn];
4403
4404 BOOL isCtrlDown = [gameView isCtrlDown];
4405
4406 double flightArrowKeyPrecisionFactor = [[NSUserDefaults standardUserDefaults] oo_doubleForKey:@"flight-arrow-key-precision-factor" defaultValue:0.5];
4407 if (flightArrowKeyPrecisionFactor < 0.05) flightArrowKeyPrecisionFactor = 0.05;
4408 if (flightArrowKeyPrecisionFactor > 1.0) flightArrowKeyPrecisionFactor = 1.0;
4409
4410 rolling = NO;
4411 // if we have yaw on the mouse x-axis, then allow using the keyboard roll keys
4412 if (!mouse_control_on || (mouse_control_on && mouse_x_axis_map_to_yaw))
4413 {
4414 if ([self checkNavKeyPress:n_key_roll_left] && [self checkNavKeyPress:n_key_roll_right])
4415 {
4416 keyboardRollOverride = YES;
4417 flightRoll = 0.0;
4418 }
4419 else if ([self checkNavKeyPress:n_key_roll_left] && !capsLockCustomView)
4420 {
4421 keyboardRollOverride=YES;
4422 if (flightRoll > 0.0) flightRoll = 0.0;
4423 [self decrease_flight_roll:isCtrlDown ? flightArrowKeyPrecisionFactor*roll_dampner*roll_delta : delta_t*roll_delta];
4424 rolling = YES;
4425 }
4426 else if ([self checkNavKeyPress:n_key_roll_right] && !capsLockCustomView)
4427 {
4428 keyboardRollOverride=YES;
4429 if (flightRoll < 0.0) flightRoll = 0.0;
4430 [self increase_flight_roll:isCtrlDown ? flightArrowKeyPrecisionFactor*roll_dampner*roll_delta : delta_t*roll_delta];
4431 rolling = YES;
4432 }
4433 }
4434 if(((mouse_control_on && !mouse_x_axis_map_to_yaw) || numSticks) && !keyboardRollOverride && !capsLockCustomView)
4435 {
4436 stick_roll = max_flight_roll * virtualStick.x;
4437 if (flightRoll < stick_roll)
4438 {
4439 [self increase_flight_roll:delta_t*roll_delta];
4440 if (flightRoll > stick_roll)
4441 flightRoll = stick_roll;
4442 }
4443 if (flightRoll > stick_roll)
4444 {
4445 [self decrease_flight_roll:delta_t*roll_delta];
4446 if (flightRoll < stick_roll)
4447 flightRoll = stick_roll;
4448 }
4449 rolling = (fabs(virtualStick.x) > 0.0);
4450 }
4451 if (!rolling)
4452 {
4453 if (flightRoll > 0.0)
4454 {
4455 if (flightRoll > roll_dampner) [self decrease_flight_roll:roll_dampner];
4456 else flightRoll = 0.0;
4457 }
4458 if (flightRoll < 0.0)
4459 {
4460 if (flightRoll < -roll_dampner) [self increase_flight_roll:roll_dampner];
4461 else flightRoll = 0.0;
4462 }
4463 }
4464
4465 pitching = NO;
4466 // we don't care about pitch keyboard overrides when mouse control is on, only when using joystick
4467 if (!mouse_control_on)
4468 {
4469 if ([self checkNavKeyPress:n_key_pitch_back] && [self checkNavKeyPress:n_key_pitch_forward])
4470 {
4471 keyboardPitchOverride=YES;
4472 flightPitch = 0.0;
4473 }
4474 else if ([self checkNavKeyPress:n_key_pitch_back] && !capsLockCustomView)
4475 {
4476 keyboardPitchOverride=YES;
4477 if (flightPitch < 0.0) flightPitch = 0.0;
4478 [self increase_flight_pitch:isCtrlDown ? flightArrowKeyPrecisionFactor*pitch_dampner*pitch_delta : delta_t*pitch_delta];
4479 pitching = YES;
4480 }
4481 else if ([self checkNavKeyPress:n_key_pitch_forward] && !capsLockCustomView)
4482 {
4483 keyboardPitchOverride=YES;
4484 if (flightPitch > 0.0) flightPitch = 0.0;
4485 [self decrease_flight_pitch:isCtrlDown ? flightArrowKeyPrecisionFactor*pitch_dampner*pitch_delta : delta_t*pitch_delta];
4486 pitching = YES;
4487 }
4488 }
4489 if((mouse_control_on || (numSticks && !keyboardPitchOverride)) && !capsLockCustomView)
4490 {
4491 stick_pitch = max_flight_pitch * virtualStick.y;
4492 if (flightPitch < stick_pitch)
4493 {
4494 [self increase_flight_pitch:delta_t*pitch_delta];
4495 if (flightPitch > stick_pitch)
4496 flightPitch = stick_pitch;
4497 }
4498 if (flightPitch > stick_pitch)
4499 {
4500 [self decrease_flight_pitch:delta_t*pitch_delta];
4501 if (flightPitch < stick_pitch)
4502 flightPitch = stick_pitch;
4503 }
4504 pitching = (fabs(virtualStick.y) > 0.0);
4505 }
4506 if (!pitching)
4507 {
4508 if (flightPitch > 0.0)
4509 {
4510 if (flightPitch > pitch_dampner) [self decrease_flight_pitch:pitch_dampner];
4511 else flightPitch = 0.0;
4512 }
4513 if (flightPitch < 0.0)
4514 {
4515 if (flightPitch < -pitch_dampner) [self increase_flight_pitch:pitch_dampner];
4516 else flightPitch = 0.0;
4517 }
4518 }
4519
4520 yawing = NO;
4521 // if we have roll on the mouse x-axis, then allow using the keyboard yaw keys
4522 if (!mouse_control_on || (mouse_control_on && !mouse_x_axis_map_to_yaw))
4523 {
4524 if ([self checkNavKeyPress:n_key_yaw_left] && [self checkNavKeyPress:n_key_yaw_right])
4525 {
4526 keyboardYawOverride=YES;
4527 flightYaw = 0.0;
4528 }
4529 else if ([self checkNavKeyPress:n_key_yaw_left] && !capsLockCustomView)
4530 {
4531 keyboardYawOverride=YES;
4532 if (flightYaw < 0.0) flightYaw = 0.0;
4533 [self increase_flight_yaw:isCtrlDown ? flightArrowKeyPrecisionFactor*yaw_dampner*yaw_delta : delta_t*yaw_delta];
4534 yawing = YES;
4535 }
4536 else if ([self checkNavKeyPress:n_key_yaw_right] && !capsLockCustomView)
4537 {
4538 keyboardYawOverride=YES;
4539 if (flightYaw > 0.0) flightYaw = 0.0;
4540 [self decrease_flight_yaw:isCtrlDown ? flightArrowKeyPrecisionFactor*yaw_dampner*yaw_delta : delta_t*yaw_delta];
4541 yawing = YES;
4542 }
4543 }
4544 if(((mouse_control_on && mouse_x_axis_map_to_yaw) || numSticks) && !keyboardYawOverride && !capsLockCustomView)
4545 {
4546 // I think yaw is handled backwards in the code,
4547 // which is why the negative sign is here.
4548 stick_yaw = max_flight_yaw * (-reqYaw);
4549 if (flightYaw < stick_yaw)
4550 {
4551 [self increase_flight_yaw:delta_t*yaw_delta];
4552 if (flightYaw > stick_yaw)
4553 flightYaw = stick_yaw;
4554 }
4555 if (flightYaw > stick_yaw)
4556 {
4557 [self decrease_flight_yaw:delta_t*yaw_delta];
4558 if (flightYaw < stick_yaw)
4559 flightYaw = stick_yaw;
4560 }
4561 yawing = (fabs(reqYaw) > 0.0);
4562 }
4563 if (!yawing)
4564 {
4565 if (flightYaw > 0.0)
4566 {
4567 if (flightYaw > yaw_dampner) [self decrease_flight_yaw:yaw_dampner];
4568 else flightYaw = 0.0;
4569 }
4570 if (flightYaw < 0.0)
4571 {
4572 if (flightYaw < -yaw_dampner) [self increase_flight_yaw:yaw_dampner];
4573 else flightYaw = 0.0;
4574 }
4575 }
4576
4577}
4578
4579
4580- (void) pollGuiScreenControls
4581{
4582 [self pollGuiScreenControlsWithFKeyAlias:YES];
4583}
4584
4585
4586- (void) pollGuiScreenControlsWithFKeyAlias:(BOOL)fKeyAlias
4587{
4588 if(!pollControls && fKeyAlias) // Still OK to run, if we don't use number keys.
4589 return;
4590
4591 GuiDisplayGen *gui = [UNIVERSE gui];
4592 MyOpenGLView *gameView = [UNIVERSE gameView];
4593 BOOL docked_okay = ([self status] == STATUS_DOCKED);
4594
4595 // text displays
4596 if ([self checkKeyPress:n_key_gui_screen_status fKey_only:!fKeyAlias])
4597 {
4599 {
4601 if (gui_screen == GUI_SCREEN_STATUS)
4602 {
4603 [self noteGUIWillChangeTo:GUI_SCREEN_MANIFEST];
4604 [self setGuiToManifestScreen];
4605 }
4606 else
4607 [self setGuiToStatusScreen];
4608 [self checkScript];
4609 }
4610 }
4611 else
4612 {
4614 }
4615
4616 if ([self checkKeyPress:n_key_gui_chart_screens fKey_only:!fKeyAlias])
4617 {
4618 mouse_left_down = NO;
4619 [gameView clearMouse];
4621 {
4623 // handles http://aegidian.org/bb/viewtopic.php?p=233189#p233189
4624 if (EXPECT_NOT([self status] == STATUS_WITCHSPACE_COUNTDOWN && gui_screen == GUI_SCREEN_SHORT_RANGE_CHART))
4625 {
4626 // don't switch to LRC if countdown in progress
4628 }
4629 else if (gui_screen == GUI_SCREEN_SHORT_RANGE_CHART || (gui_screen == GUI_SCREEN_SYSTEM_DATA && showingLongRangeChart))
4630 {
4631 if (target_chart_zoom != CHART_MAX_ZOOM)
4632 {
4633 saved_chart_zoom = target_chart_zoom;
4634 }
4635 target_chart_zoom = CHART_MAX_ZOOM;
4636 [self noteGUIWillChangeTo:GUI_SCREEN_LONG_RANGE_CHART];
4637 [self setGuiToLongRangeChartScreen];
4638 }
4639 else
4640 {
4641 if (target_chart_zoom == CHART_MAX_ZOOM)
4642 {
4643 target_chart_zoom = saved_chart_zoom;
4644 }
4645 //target_chart_centre = cursor_coordinates = [[UNIVERSE systemManager] getCoordinatesForSystem:target_system_id inGalaxy:galaxy_number];
4646 [self noteGUIWillChangeTo:GUI_SCREEN_SHORT_RANGE_CHART];
4647 [self setGuiToShortRangeChartScreen];
4648 }
4649 }
4650 }
4651 else
4652 {
4654 }
4655
4656 if ([self checkKeyPress:n_key_gui_system_data fKey_only:!fKeyAlias])
4657 {
4658 if (gui_screen != GUI_SCREEN_SYSTEM_DATA)
4659 {
4660 showingLongRangeChart = (gui_screen == GUI_SCREEN_LONG_RANGE_CHART);
4661 [self noteGUIWillChangeTo:GUI_SCREEN_SYSTEM_DATA];
4662 [self setGuiToSystemDataScreen];
4663 }
4664 }
4665
4666 if ([self checkKeyPress:n_key_gui_market fKey_only:!fKeyAlias])
4667 {
4668 if (gui_screen != GUI_SCREEN_MARKET)
4669 {
4670 [gameView clearKeys];
4671 [self noteGUIWillChangeTo:GUI_SCREEN_MARKET];
4672 [self setGuiToMarketScreen];
4673 }
4674 else
4675 {
4676 [gameView clearKeys];
4677 [self noteGUIWillChangeTo:GUI_SCREEN_MARKETINFO];
4678 [self setGuiToMarketInfoScreen];
4679 }
4680 }
4681
4682
4683 if (docked_okay)
4684 {
4685 if (([self checkKeyPress:n_key_gui_screen_options fKey_only:!fKeyAlias]) && (gui_screen != GUI_SCREEN_OPTIONS))
4686 {
4687 [gameView clearKeys];
4688 [self setGuiToLoadSaveScreen];
4689 }
4690
4691 if ([self checkKeyPress:n_key_gui_screen_equipship fKey_only:!fKeyAlias])
4692 {
4694 {
4695 if ([self dockedStation] == nil) [self setDockedAtMainStation];
4696 OOGUIScreenID oldScreen = gui_screen;
4697
4698 if ((gui_screen == GUI_SCREEN_EQUIP_SHIP) && [[self dockedStation] hasShipyard])
4699 {
4700 [gameView clearKeys];
4701 [self noteGUIWillChangeTo:GUI_SCREEN_SHIPYARD];
4702 [self setGuiToShipyardScreen:0];
4703 [gui setSelectedRow:GUI_ROW_SHIPYARD_START];
4704 [self showShipyardInfoForSelection];
4705 }
4706 else
4707 {
4708 [gameView clearKeys];
4709 [self noteGUIWillChangeTo:GUI_SCREEN_EQUIP_SHIP];
4710 [self setGuiToEquipShipScreen:0];
4711 [gui setSelectedRow:GUI_ROW_EQUIPMENT_START];
4712 }
4713
4714 [self noteGUIDidChangeFrom:oldScreen to:gui_screen];
4715 }
4717 }
4718 else
4719 {
4721 }
4722
4723 if ([self checkKeyPress:n_key_gui_screen_interfaces fKey_only:!fKeyAlias])
4724 {
4725 [self setGuiToInterfacesScreen:0];
4726 [gui setSelectedRow:GUI_ROW_INTERFACES_START];
4727 }
4728
4729 }
4730}
4731
4732
4733- (void) pollGameOverControls:(double)delta_t
4734{
4735 MyOpenGLView *gameView = [UNIVERSE gameView];
4736 if ([gameView isDown:32]) // look for the spacebar
4737 {
4738 if (!spacePressed)
4739 {
4740 [UNIVERSE displayMessage:@"" forCount:1.0];
4741 shot_time = INITIAL_SHOT_TIME; // forces immediate restart
4742 }
4743 spacePressed = YES;
4744 }
4745 else
4746 spacePressed = NO;
4747}
4748
4749
4750static BOOL toggling_music;
4751static BOOL playing_music;
4753
4754- (void) pollAutopilotControls:(double)delta_t
4755{
4756 // don't do anything if we're configuring the keyboard
4757 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;
4758
4759 const BOOL *joyButtonState = [[OOJoystickManager sharedStickHandler] getAllButtonStates];
4760
4761 // controls polled while the autopilot is active
4762 if (![[UNIVERSE gameController] isGamePaused])
4763 {
4764 // view keys
4765 [self pollViewControls];
4766
4767 // text displays
4768 [self pollGuiScreenControls];
4769
4770 if ([UNIVERSE displayGUI])
4771 [self pollGuiArrowKeyControls:delta_t];
4772
4773 if ([self checkKeyPress:n_key_autopilot] || joyButtonState[BUTTON_DOCKCPU]
4774 || [self checkKeyPress:n_key_autodock] || joyButtonState[BUTTON_DOCKCPUFAST]) // look for the 'c' and 'C' key
4775 {
4776 if ([self hasDockingComputer] && !autopilot_key_pressed && !fast_autopilot_key_pressed)
4777 {
4778 [self disengageAutopilot];
4779 [UNIVERSE addMessage:DESC(@"autopilot-off") forCount:4.5];
4780 }
4782 if ([self checkKeyPress:n_key_autodock] || joyButtonState[BUTTON_DOCKCPUFAST])
4783 {
4785 }
4786 }
4787 else
4788 {
4791 }
4792
4793 if (([self checkKeyPress:n_key_docking_music] || joyButtonState[BUTTON_DOCKINGMUSIC])) // look for the 's' key
4794 {
4795 if (!toggling_music)
4796 {
4798 }
4799 toggling_music = YES;
4800 }
4801 else
4802 {
4803 toggling_music = NO;
4804 }
4805 // look for the pause game, 'p' key
4806 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)
4807 {
4808 if (!autopilot_pause)
4809 {
4812 // normal flight controls can handle the rest.
4813 pause_pressed = NO; // pause button flag must be NO for pollflightControls to react!
4814 [self pollFlightControls:delta_t];
4815 }
4816 autopilot_pause = YES;
4817 }
4818 else
4819 {
4820 autopilot_pause = NO;
4821 }
4822 }
4823 else
4824 {
4825 // paused
4826 if ([self checkKeyPress:n_key_pausebutton] || joyButtonState[BUTTON_PAUSE])
4827 {
4828 if (!autopilot_pause)
4829 {
4831 }
4832 autopilot_pause = YES;
4833 }
4834 else
4835 {
4836 autopilot_pause = NO;
4837 }
4838 // let the normal flight controls handle paused commands.
4839 [self pollFlightControls:delta_t];
4840 }
4841}
4842
4843
4844- (void) pollDockedControls:(double)delta_t
4845{
4846 MyOpenGLView *gameView = [UNIVERSE gameView];
4847 GameController *gameController = [UNIVERSE gameController];
4848 const BOOL *joyButtonState = [[OOJoystickManager sharedStickHandler] getAllButtonStates];
4849 NSString *exceptionContext = @"setup";
4850
4851 @try
4852 {
4853 // Pause game, 'p' key
4854 exceptionContext = @"pause key";
4855 if (([self checkKeyPress:n_key_pausebutton] || joyButtonState[BUTTON_PAUSE]) && (gui_screen != GUI_SCREEN_LONG_RANGE_CHART &&
4856 gui_screen != GUI_SCREEN_MISSION && gui_screen != GUI_SCREEN_REPORT &&
4857 gui_screen != GUI_SCREEN_SAVE && gui_screen != GUI_SCREEN_KEYBOARD_ENTRY) )
4858 {
4859 if (!pause_pressed)
4860 {
4861 if ([gameController isGamePaused])
4862 {
4863 script_time = saved_script_time;
4864 [gameView allowStringInput:NO];
4865 if ([UNIVERSE pauseMessageVisible])
4866 {
4867 [UNIVERSE clearPreviousMessage]; // remove the 'paused' message.
4868 }
4869 [[UNIVERSE gui] setForegroundTextureKey:@"docked_overlay"];
4870 [gameController setGamePaused:NO];
4871 }
4872 else
4873 {
4874 saved_script_time = script_time;
4875 [[UNIVERSE messageGUI] clear];
4876
4877 [UNIVERSE pauseGame]; // 'paused' handler
4878 }
4879 }
4880 pause_pressed = YES;
4881 }
4882 else
4883 {
4884 pause_pressed = NO;
4885 }
4886
4887 if ([gameController isGamePaused]) return;
4888
4889 if(pollControls)
4890 {
4891 exceptionContext = @"undock";
4892 if ([self checkKeyPress:n_key_launch_ship])
4893 {
4894 if (EXPECT((gui_screen != GUI_SCREEN_MISSION || _missionAllowInterrupt) && gui_screen != GUI_SCREEN_KEYBOARD_ENTRY))
4895 {
4896 [self handleUndockControl];
4897 }
4898 }
4899 }
4900
4901 // text displays
4902 // mission screens
4903 exceptionContext = @"GUI keys";
4904 if (gui_screen == GUI_SCREEN_MISSION || gui_screen == GUI_SCREEN_KEYBOARD_ENTRY)
4905 {
4906 [self pollDemoControls: delta_t]; // don't switch away from mission screens
4907 }
4908 else
4909 {
4910 if (gui_screen != GUI_SCREEN_REPORT)[self pollGuiScreenControls]; // don't switch away from report screens
4911 }
4912
4913 [self pollGuiArrowKeyControls:delta_t];
4914 }
4915 @catch (NSException *exception)
4916 {
4917 OOLog(kOOLogException, @"***** Exception in pollDockedControls [%@]: %@ : %@", exceptionContext, [exception name], [exception reason]);
4918 }
4919}
4920
4921
4922- (void) handleUndockControl
4923{
4924 // FIXME: should this not be in leaveDock:? (Note: leaveDock: is also called from script method launchFromStation and -[StationEntity becomeExplosion]) -- Ahruman 20080308
4925 [UNIVERSE setUpUniverseFromStation]; // player pre-launch
4926 if ([self dockedStation] == nil) [self setDockedAtMainStation];
4927
4928 StationEntity *dockedStation = [self dockedStation];
4929 if (dockedStation == [UNIVERSE station] && [UNIVERSE autoSaveNow] && !([[UNIVERSE sun] goneNova] || [[UNIVERSE sun] willGoNova]))
4930 {
4931 [self autosavePlayer];
4932 }
4933 [self launchFromStation];
4934}
4935
4936
4937- (void) pollDemoControls:(double)delta_t
4938{
4939 MyOpenGLView *gameView = [UNIVERSE gameView];
4940 GuiDisplayGen *gui = [UNIVERSE gui];
4941 NSUInteger end_row = 21;
4942 OOOXZManager *oxzmanager = [OOOXZManager sharedManager];
4943
4944 switch (gui_screen)
4945 {
4946 case GUI_SCREEN_INTRO1:
4947 [self handleGUIUpDownArrowKeys];
4948
4949 int row_zero = 21;
4950 if (!selectPressed)
4951 {
4953 {
4954 if (([gameView isDown:gvMouseDoubleClick] || [self checkKeyPress:n_key_gui_select]) && [gui selectedRow] == 2+row_zero)
4955 {
4957 [UNIVERSE removeDemoShips];
4958 [gui clearBackground];
4959 if (![self loadPlayer])
4960 {
4961 [self setGuiToIntroFirstGo:YES];
4962 }
4963 break;
4964 }
4965 }
4966 if (([gameView isDown:gvMouseDoubleClick] || [self checkKeyPress:n_key_gui_select]) && [gui selectedRow] == 1+row_zero)
4967 {
4968 missionTextRow = 0;
4969 [self setGuiToScenarioScreen:0];
4970 }
4971 else if (([gameView isDown:gvMouseDoubleClick] || [self checkKeyPress:n_key_gui_select]) && [gui selectedRow] == 3+row_zero)
4972 {
4973 [self setGuiToIntroFirstGo:NO];
4974 }
4975 else if (([gameView isDown:gvMouseDoubleClick] || [self checkKeyPress:n_key_gui_select]) && [gui selectedRow] == 4+row_zero)
4976 {
4977 [self setGuiToGameOptionsScreen];
4978 }
4979 else if (([gameView isDown:gvMouseDoubleClick] || [self checkKeyPress:n_key_gui_select]) && [gui selectedRow] == 5+row_zero)
4980 {
4981 [self setGuiToOXZManager];
4982 }
4983 else if (([gameView isDown:gvMouseDoubleClick] || [self checkKeyPress:n_key_gui_select]) && [gui selectedRow] == 6+row_zero)
4984 {
4985 [[UNIVERSE gameController] exitAppWithContext:@"Exit Game selected on start screen"];
4986 }
4987 else
4988 {
4990 }
4991 }
4992 selectPressed = [self checkKeyPress:n_key_gui_select];
4993 if ([gameView isDown:gvMouseDoubleClick])
4994 {
4995 [gameView clearMouse];
4996 }
4997 break;
4998
4999 case GUI_SCREEN_GAMEOPTIONS:
5000 [self handleGameOptionsScreenKeys];
5001 break;
5002
5003 case GUI_SCREEN_KEYBOARD:
5004 //if ([gameView isDown:' ']) // '<space>'
5005 //{
5006 // [self setGuiToIntroFirstGo:YES];
5007 //}
5008 [self handleKeyMapperScreenKeys];
5009 break;
5010
5011 case GUI_SCREEN_KEYBOARD_CONFIRMCLEAR:
5012 [self handleKeyMapperConfirmClearKeys:gui view:gameView];
5013 break;
5014
5015 case GUI_SCREEN_KEYBOARD_CONFIG:
5016 [self handleKeyConfigKeys:gui view:gameView];
5017 break;
5018
5019 case GUI_SCREEN_KEYBOARD_ENTRY:
5020 [self handleKeyConfigEntryKeys:gui view:gameView];
5021 break;
5022
5023 case GUI_SCREEN_KEYBOARD_LAYOUT:
5024 [self handleKeyboardLayoutKeys];
5025 break;
5026
5027 case GUI_SCREEN_STICKMAPPER:
5028 [self handleStickMapperScreenKeys];
5029 break;
5030
5031 case GUI_SCREEN_STICKPROFILE:
5032 [self stickProfileInputHandler:gui view:gameView];
5033 break;
5034
5035 case GUI_SCREEN_SHIPLIBRARY:
5036 if ([gameView isDown:' ']) // '<space>'
5037 {
5038 // viewed from start screen, return to it
5039 [self setGuiToIntroFirstGo:YES];
5040 }
5041 if ([self checkKeyPress:n_key_gui_arrow_up]) // '<--'
5042 {
5043 if (!upDownKeyPressed)
5044 [UNIVERSE selectIntro2Previous];
5045 }
5046 if ([self checkKeyPress:n_key_gui_arrow_down]) // '-->'
5047 {
5048 if (!upDownKeyPressed)
5049 [UNIVERSE selectIntro2Next];
5050 }
5051 upDownKeyPressed = (([self checkKeyPress:n_key_gui_arrow_up])||([self checkKeyPress:n_key_gui_arrow_down]));
5052
5053 if ([self checkKeyPress:n_key_gui_arrow_left]) // '<--'
5054 {
5056 [UNIVERSE selectIntro2PreviousCategory];
5057 }
5058 if ([self checkKeyPress:n_key_gui_arrow_right]) // '-->'
5059 {
5061 [UNIVERSE selectIntro2NextCategory];
5062 }
5063 leftRightKeyPressed = (([self checkKeyPress:n_key_gui_arrow_left])||([self checkKeyPress:n_key_gui_arrow_right]));
5064
5065
5066 break;
5067
5068 case GUI_SCREEN_NEWGAME:
5069 if ([self handleGUIUpDownArrowKeys])
5070 {
5071 [self showScenarioDetails];
5072 }
5073
5075 {
5076 if ([self checkKeyPress:n_key_gui_page_up])
5077 {
5078 // find the Back <<< line, select it and press it
5079 if ([[gui keyForRow:GUI_ROW_SCENARIOS_START - 1] hasPrefix:@"__page"])
5080 {
5081 if ([gui setSelectedRow:GUI_ROW_SCENARIOS_START - 1])
5082 {
5083 [self startScenario];
5084 }
5085 }
5086
5087 }
5088 else if ([self checkKeyPress:n_key_gui_page_down])
5089 {
5090 // find the Next >>> line, select it and press it
5091 if ([[gui keyForRow:GUI_ROW_SCENARIOS_START + GUI_MAX_ROWS_SCENARIOS] hasPrefix:@"__page"])
5092 {
5093 if ([gui setSelectedRow:GUI_ROW_SCENARIOS_START + GUI_MAX_ROWS_SCENARIOS])
5094 {
5095 [self startScenario];
5096 }
5097 }
5098 }
5099 }
5100 pageUpDownKeyPressed = [self checkKeyPress:n_key_gui_page_down]|[self checkKeyPress:n_key_gui_page_up];
5101
5102 if (!selectPressed)
5103 {
5104 if ([self checkKeyPress:n_key_gui_select] || [gameView isDown:gvMouseDoubleClick]) // enter
5105 {
5106 if (![self startScenario])
5107 {
5108 [UNIVERSE removeDemoShips];
5109 [self setGuiToIntroFirstGo:YES];
5110 }
5111 }
5112 }
5113 selectPressed = [self checkKeyPress:n_key_gui_select];
5114 if ([gameView isDown:gvMouseDoubleClick] || [gameView isDown:gvMouseLeftButton])
5115 {
5116 [gameView clearMouse];
5117 }
5118 break;
5119
5120 case GUI_SCREEN_OXZMANAGER:
5121 // release locks on music on this screen
5123 if (EXPECT(![oxzmanager isRestarting]))
5124 {
5125 if ([oxzmanager isAcceptingGUIInput])
5126 {
5127 if ([oxzmanager isAcceptingTextInput])
5128 {
5129 [gameView setStringInput: gvStringInputAll];
5130 [oxzmanager refreshTextInput:[gameView typedString]];
5131 }
5132 else
5133 {
5134 [gameView allowStringInput: NO];
5135 }
5136 if ([self handleGUIUpDownArrowKeys])
5137 {
5138 // only has an effect on install/remove selection screens
5139 [oxzmanager showOptionsUpdate];
5140 }
5141 if ([self checkKeyPress:n_key_gui_arrow_left] || [self checkKeyPress:n_key_gui_page_up])
5142 {
5143 if ((!leftRightKeyPressed))
5144 {
5145 [oxzmanager processOptionsPrev];
5146 }
5147 }
5148 else if ([self checkKeyPress:n_key_gui_arrow_right] || [self checkKeyPress:n_key_gui_page_down])
5149 {
5150 if ((!leftRightKeyPressed))
5151 {
5152 [oxzmanager processOptionsNext];
5153 }
5154 }
5155 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];
5156
5157 if (!selectPressed)
5158 {
5159 if ([self checkKeyPress:n_key_gui_select] || [gameView isDown:gvMouseDoubleClick]) // enter
5160 {
5161 if ([oxzmanager isAcceptingTextInput])
5162 {
5163 [oxzmanager processTextInput:[gameView typedString]];
5164 }
5165 else
5166 {
5167 [oxzmanager processSelection];
5168 }
5169 }
5170 }
5171 selectPressed = [self checkKeyPress:n_key_gui_select];
5172 if ([gameView isDown:gvMouseDoubleClick] || [gameView isDown:gvMouseLeftButton])
5173 {
5174 [gameView clearMouse];
5175 }
5176 } // endif isAcceptingGUIInput
5177 if ([self checkKeyPress:n_key_oxzmanager_setfilter] ||
5178 [self checkKeyPress:n_key_oxzmanager_showinfo] ||
5179 [self checkKeyPress:n_key_oxzmanager_extract])
5180 {
5182 {
5183 oxz_manager_pressed = YES;
5184 if ([self checkKeyPress:n_key_oxzmanager_setfilter])
5185 {
5186 [oxzmanager processFilterKey];
5187 }
5188 else if ([self checkKeyPress:n_key_oxzmanager_showinfo])
5189 {
5190 [oxzmanager processShowInfoKey];
5191 }
5192 else if ([self checkKeyPress:n_key_oxzmanager_extract])
5193 {
5194 [oxzmanager processExtractKey];
5195 }
5196
5197 }
5198 }
5199 else
5200 {
5202 }
5203 }
5204 break;
5205
5206
5207
5208 case GUI_SCREEN_MISSION:
5209 if ([[self hud] allowBigGui])
5210 {
5211 end_row = 27;
5212 }
5213 if (_missionTextEntry)
5214 {
5215 [self refreshMissionScreenTextEntry];
5216 if ([self checkKeyPress:n_key_gui_select] || [gameView isDown:gvMouseDoubleClick]) // '<enter/return>' or double click
5217 {
5218 [self setMissionChoice:[gameView typedString] keyPress:@"enter"];
5220 [self playDismissedMissionScreen];
5221
5222 [self handleMissionCallback];
5223
5224 [self checkScript];
5225 selectPressed = YES;
5226 pollControls = YES;
5227 }
5228 else
5229 {
5230 pollControls = NO;
5231 selectPressed = NO;
5232 [self pollMissionInterruptControls];
5233 }
5234 }
5235 else if ([[gui keyForRow:end_row] isEqual:@"spacebar"])
5236 {
5237 if ([gameView isDown:32]) // '<space>'
5238 {
5239 if (!spacePressed)
5240 {
5242 [self handleMissionCallback];
5243
5244 }
5245 spacePressed = YES;
5246 }
5247 else
5248 {
5249 spacePressed = NO;
5250 [self pollMissionInterruptControls];
5251 }
5252 }
5253 else
5254 {
5255 [self handleGUIUpDownArrowKeys];
5256 NSString *extraKey = @"";
5257 if (extraMissionKeys)
5258 {
5259 NSString *key = nil;
5260 foreach (key, [extraMissionKeys allKeys])
5261 {
5262 if ([self checkKeyPress:[extraMissionKeys oo_arrayForKey:key]]) {
5263 if (!extra_key_pressed)
5264 {
5265 extraKey = [key copy];
5266 }
5267 extra_key_pressed = YES;
5268 }
5269 else
5270 extra_key_pressed = NO;
5271 }
5272 }
5273 if ([self checkKeyPress:n_key_gui_select] || [gameView isDown:gvMouseDoubleClick] || [extraKey length] > 0) // '<enter/return>' or double click
5274 {
5275 if ([gameView isDown:gvMouseDoubleClick])
5276 {
5277 selectPressed = NO;
5278 [gameView clearMouse];
5279 }
5280 if (!selectPressed)
5281 {
5282 if ([extraKey length] == 0) extraKey = @"enter";
5283 [self setMissionChoice:[gui selectedRowKey] keyPress:extraKey];
5285 [self playDismissedMissionScreen];
5286
5287 [self handleMissionCallback];
5288
5289 [self checkScript];
5290 }
5291 selectPressed = YES;
5292 }
5293 else
5294 {
5295 selectPressed = NO;
5296 [self pollMissionInterruptControls];
5297 }
5298 [extraKey release];
5299 }
5300 break;
5301
5302#if OO_USE_CUSTOM_LOAD_SAVE
5303 // DJS: Farm off load/save screen options to LoadSave.m
5304 case GUI_SCREEN_LOAD:
5305 {
5306 NSString *commanderFile = [self commanderSelector];
5307 if(commanderFile)
5308 {
5309 // also release the demo ship here (see showShipyardModel and noteGUIDidChangeFrom)
5310 [demoShip release];
5311 demoShip = nil;
5312
5313 [self loadPlayerFromFile:commanderFile asNew:NO];
5314 }
5315 break;
5316 }
5317#endif
5318
5319 default:
5320 break;
5321 }
5322}
5323
5324
5325- (void) pollMissionInterruptControls
5326{
5327 if (_missionAllowInterrupt)
5328 {
5329 if (gui_screen == GUI_SCREEN_MISSION && _missionTextEntry)
5330 {
5331 [self pollGuiScreenControlsWithFKeyAlias:NO];
5332 }
5333 else {
5334 [self pollGuiScreenControls];
5335 }
5336 if (gui_screen != GUI_SCREEN_MISSION)
5337 {
5338 if (gui_screen != GUI_SCREEN_SYSTEM_DATA)
5339 {
5340 [UNIVERSE removeDemoShips];
5341 }
5342 [self endMissionScreenAndNoteOpportunity];
5343 }
5344 }
5345}
5346
5347
5348- (void) handleMissionCallback
5349{
5350 [UNIVERSE removeDemoShips];
5351 [[UNIVERSE gui] clearBackground];
5352
5353 [self setGuiToMissionEndScreen]; // need this to find out if we call a new mission screen inside callback.
5354
5355 if ([self status] != STATUS_DOCKED) [self switchToThisView:VIEW_FORWARD];
5356
5357 if (_missionWithCallback)
5358 {
5359 [self doMissionCallback];
5360 }
5361
5362 if ([self status] != STATUS_DOCKED) // did we launch inside callback? / are we in flight?
5363 {
5364 // TODO: This is no longer doing anything because of an 'isDocked' check inside the function. ***** Probably remove it for 1.76
5365 [self doWorldEventUntilMissionScreen:OOJSID("missionScreenEnded")]; // no opportunity events.
5366 }
5367 else
5368 {
5369 if (gui_screen != GUI_SCREEN_MISSION) // did we call a new mission screen inside callback?
5370 {
5371 // note that this might not be the same end screen as last time...
5372 [self setGuiToMissionEndScreen]; // if not, update status screen with callback changes, if any.
5373 [self endMissionScreenAndNoteOpportunity]; // missionScreenEnded, plus opportunity events.
5374 }
5375 }
5376}
5377
5378
5379- (void) setGuiToMissionEndScreen
5380{
5381 MyOpenGLView *gameView = [UNIVERSE gameView];
5382 [gameView clearKeys];
5383 if ([self status] != STATUS_DOCKED)
5384 {
5385 // this setting is only applied when not docked
5386 [self setGuiToStatusScreen];
5387 return;
5388 }
5389 switch (_missionExitScreen)
5390 {
5391 case GUI_SCREEN_MANIFEST:
5392 [self noteGUIWillChangeTo:GUI_SCREEN_MANIFEST];
5393 [self setGuiToManifestScreen];
5394 break;
5395 case GUI_SCREEN_EQUIP_SHIP:
5396 [self noteGUIWillChangeTo:GUI_SCREEN_EQUIP_SHIP];
5397 [self setGuiToEquipShipScreen:0];
5398 break;
5399 case GUI_SCREEN_SHIPYARD:
5400 if ([[self dockedStation] hasShipyard])
5401 {
5402 [self noteGUIWillChangeTo:GUI_SCREEN_SHIPYARD];
5403 [self setGuiToShipyardScreen:0];
5404 [[UNIVERSE gui] setSelectedRow:GUI_ROW_SHIPYARD_START];
5405 [self showShipyardInfoForSelection];
5406 }
5407 else
5408 {
5409 // that doesn't work here
5410 [self setGuiToStatusScreen];
5411 }
5412 break;
5413 case GUI_SCREEN_LONG_RANGE_CHART:
5414 [self setGuiToLongRangeChartScreen];
5415 break;
5416 case GUI_SCREEN_SHORT_RANGE_CHART:
5417 [self setGuiToShortRangeChartScreen];
5418 break;
5419 case GUI_SCREEN_SYSTEM_DATA:
5420 [self noteGUIWillChangeTo:GUI_SCREEN_SYSTEM_DATA];
5421 [self setGuiToSystemDataScreen];
5422 break;
5423 case GUI_SCREEN_MARKET:
5424 [self noteGUIWillChangeTo:GUI_SCREEN_MARKET];
5425 [self setGuiToMarketScreen];
5426 break;
5427 case GUI_SCREEN_MARKETINFO:
5428 [self noteGUIWillChangeTo:GUI_SCREEN_MARKETINFO];
5429 [self setGuiToMarketInfoScreen];
5430 break;
5431 case GUI_SCREEN_INTERFACES:
5432 [self setGuiToInterfacesScreen:0];
5433 break;
5434 case GUI_SCREEN_STATUS:
5435 default: // invalid screen specifications
5436 [self setGuiToStatusScreen];
5437 }
5438}
5439
5440
5441- (void) switchToThisView:(OOViewID)viewDirection
5442{
5443 [self switchToThisView:viewDirection andProcessWeaponFacing:YES];
5444}
5445
5446
5447- (void) switchToThisView:(OOViewID)viewDirection andProcessWeaponFacing:(BOOL)processWeaponFacing
5448{
5449 [self switchToThisView:viewDirection fromView:[UNIVERSE viewDirection] andProcessWeaponFacing:processWeaponFacing justNotify:NO];
5450}
5451
5452
5453- (void) switchToThisView:(OOViewID)viewDirection fromView:(OOViewID)oldViewDirection andProcessWeaponFacing:(BOOL)processWeaponFacing justNotify:(BOOL)justNotify
5454{
5455 if (!justNotify)
5456 {
5457 if ([UNIVERSE displayGUI]) [self switchToMainView];
5458 [UNIVERSE setViewDirection:viewDirection];
5459 }
5460 if (processWeaponFacing)
5461 {
5463 switch (viewDirection)
5464 {
5465 case VIEW_FORWARD:
5466 facing = WEAPON_FACING_FORWARD;
5467 break;
5468
5469 case VIEW_AFT:
5470 facing = WEAPON_FACING_AFT;
5471 break;
5472
5473 case VIEW_PORT:
5474 facing = WEAPON_FACING_PORT;
5475 break;
5476
5477 case VIEW_STARBOARD:
5478 facing = WEAPON_FACING_STARBOARD;
5479 break;
5480
5481 default:
5482 break;
5483 }
5484
5485 if (facing != WEAPON_FACING_NONE)
5486 {
5487 currentWeaponFacing = facing;
5488 [self currentWeaponStats];
5489 }
5490 else
5491 {
5492 OOLogERR(kOOLogParameterError, @"%s called with processWeaponFacing=YES for non-main view %i.", __FUNCTION__, viewDirection);
5493 }
5494 }
5495 if ((oldViewDirection != viewDirection || viewDirection == VIEW_CUSTOM) && ![[UNIVERSE gameController] isGamePaused])
5496 {
5497 JSContext *context = OOJSAcquireContext();
5498 ShipScriptEvent(context, self, "viewDirectionChanged", OOJSValueFromViewID(context, viewDirection), OOJSValueFromViewID(context, oldViewDirection));
5499 OOJSRelinquishContext(context);
5500 }
5501}
5502
5503
5504// Called on c or Shift-C
5505- (void) handleAutopilotOn:(BOOL)fastDocking
5506{
5507 NSString *message = nil;
5508
5509 // Check alert condition - on red alert, abort
5510 // -- but only for fast docking
5511 if (fastDocking && ([self alertCondition] == ALERT_CONDITION_RED))
5512 {
5513 [self playAutopilotCannotDockWithTarget];
5514 message = OOExpandKey(@"autopilot-red-alert");
5515 goto abort;
5516 }
5517
5518 Entity *target = [self primaryTarget];
5519 // If target isn't dockable, check for nearby stations
5520 if (![target isStation])
5521 {
5522 Universe *uni = UNIVERSE;
5523 Entity **entities = uni->sortedEntities; // grab the public sorted list
5524 int nStations = 0;
5525 unsigned i;
5526
5527 for (i = 0; i < uni->n_entities && nStations < 2; i++)
5528 {
5529 if (entities[i]->isStation && [entities[i] isKindOfClass:[StationEntity class]] &&
5530 entities[i]->zero_distance <= SCANNER_MAX_RANGE2)
5531 {
5532 nStations++;
5533 target = entities[i];
5534 }
5535 }
5536 // If inside the Aegis, dock with the main station.
5537 // If we found one target, dock with it.
5538 // If outside the Aegis and we found multiple targets, abort.
5539
5540 if ([self withinStationAegis] && legalStatus <= 50)
5541 {
5542 target = [UNIVERSE station];
5543 }
5544 else if (nStations != 1)
5545 {
5546 if (nStations == 0)
5547 {
5548 [self playAutopilotOutOfRange];
5549 message = OOExpandKey(@"autopilot-out-of-range");
5550 }
5551 else
5552 {
5553 [self playAutopilotCannotDockWithTarget];
5554 message = OOExpandKey(@"autopilot-multiple-targets");
5555 }
5556 goto abort;
5557 }
5558 }
5559
5560 // We found a dockable, check whether we can dock with it
5561 // NSAssert([target isKindOfClass:[StationEntity class]], @"Expected entity with isStation flag set to be a station."); // no need for asserts. Tested enough already.
5562 StationEntity *ts = (StationEntity *)target;
5563 NSString *stationName = [ts displayName];
5564
5565 // If station is not transmitting docking instructions, we cannot use autopilot.
5566 if (![ts allowsAutoDocking])
5567 {
5568 [self playAutopilotCannotDockWithTarget];
5569 message = OOExpandKey(@"autopilot-station-does-not-allow-autodocking", stationName);
5570 }
5571 // Deny if station is hostile or player is a fugitive trying to dock at the main station.
5572 else if ((legalStatus > 50 && ts == [UNIVERSE station]) || [ts isHostileTo:self])
5573 {
5574 [self playAutopilotCannotDockWithTarget];
5575 message = OOExpandKey((ts == [UNIVERSE station]) ? @"autopilot-denied" : @"autopilot-target-docking-instructions-denied", stationName);
5576 }
5577 // If we're fast-docking, perform the docking logic
5578 else if (fastDocking && [ts allowsFastDocking])
5579 {
5580 // check whether there are docks that do not accept docking - even one such dock will result in rejection
5581 NSEnumerator *subEnum = nil;
5582 DockEntity* sub = nil;
5583 for (subEnum = [ts dockSubEntityEnumerator]; (sub = [subEnum nextObject]); )
5584 {
5585 // TOO_BIG_TO_DOCK issued when docks are scripted to reject docking
5586 if([[sub canAcceptShipForDocking:self] isEqualToString:@"TOO_BIG_TO_DOCK"])
5587 {
5588 message = OOExpandKey((ts == [UNIVERSE station]) ? @"autopilot-denied" : @"autopilot-target-docking-instructions-denied", stationName);
5589 goto abort;
5590 }
5591 }
5592
5593 if (legalStatus > 0)
5594 {
5595 // there's a slight chance you'll be fined for your past offences when autodocking
5596 int fine_chance = ranrot_rand() & 0x03ff; // 0..1023
5597 int government = 1 + [[UNIVERSE currentSystemData] oo_intForKey:KEY_GOVERNMENT]; // 1..8
5598 if ([UNIVERSE inInterstellarSpace]) government = 2; // equivalent to Feudal. I'm assuming any station in interstellar space is military. -- Ahruman 2008-05-29
5599 fine_chance /= government;
5600 if (fine_chance < legalStatus)
5601 {
5602 [self markForFines];
5603 }
5604 }
5605
5606 [self setDockingClearanceStatus:DOCKING_CLEARANCE_STATUS_GRANTED];
5607
5608 [UNIVERSE forceWitchspaceEntries];
5609 ship_clock_adjust += 1200.0; // 20 minutes penalty to enter dock
5610 ident_engaged = NO;
5611 [self safeAllMissiles];
5612 [UNIVERSE setViewDirection:VIEW_FORWARD];
5613 [self enterDock:ts];
5614 }
5615 else
5616 {
5617 // Standard docking - engage autopilot
5618 [self engageAutopilotToStation:ts];
5619 message = OOExpandKey(@"autopilot-on");
5620 }
5621
5622abort:
5623 // Clean-up code
5624 if (message != nil) [UNIVERSE addMessage:message forCount:4.5];
5625 return;
5626}
5627
5628
5629- (void) handleButtonIdent
5630{
5631 // Clear current target if we're already in Ident mode
5632 if (ident_engaged) [self noteLostTarget];
5633
5634 [self safeAllMissiles];
5635 ident_engaged = YES;
5636 if ([self primaryTarget] == nil)
5637 {
5638 [self playIdentOn];
5639 [UNIVERSE addMessage:OOExpandKey(@"ident-on") forCount:2.0];
5640 }
5641 else
5642 {
5643 [self playIdentLockedOn];
5644 [self printIdentLockedOnForMissile:NO];
5645 }
5646}
5647
5648
5649- (void) handleButtonTargetMissile
5650{
5651 if (![self weaponsOnline])
5652 {
5653 [self handleButtonIdent];
5654 return;
5655 }
5656
5657 // Clear current target if we're already in Missile Targeting mode
5658 if (missile_status != MISSILE_STATUS_SAFE)
5659 {
5660 [self noteLostTarget];
5661 }
5662
5663 // Arm missile and check for missile lock
5664 missile_status = MISSILE_STATUS_ARMED;
5665 if ([missile_entity[activeMissile] isMissile])
5666 {
5667 if ([[self primaryTarget] isShip])
5668 {
5669 missile_status = MISSILE_STATUS_TARGET_LOCKED;
5670 [missile_entity[activeMissile] addTarget:[self primaryTarget]];
5671 [self printIdentLockedOnForMissile:YES];
5672 [self playMissileLockedOn];
5673 }
5674 else
5675 {
5676 // if it's nil, that means it was lost earlier
5677 if ([self primaryTarget] != nil)
5678 {
5679 [self noteLostTarget];
5680 }
5681 [missile_entity[activeMissile] noteLostTarget];
5682 NSString *weaponName = [missile_entity[activeMissile] name];
5683 [UNIVERSE addMessage:OOExpandKey(@"missile-armed", weaponName) forCount:2.0];
5684 [self playMissileArmed];
5685 }
5686 }
5687 else if ([missile_entity[activeMissile] isMine])
5688 {
5689 NSString *weaponName = [missile_entity[activeMissile] name];
5690 [UNIVERSE addMessage:OOExpandKey(@"mine-armed", weaponName) forCount:2.0];
5691 [self playMineArmed];
5692 }
5693 ident_engaged = NO;
5694}
5695
5696@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_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)
return self
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 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_PAPERWHITE
#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:833
#define DESC(key)
Definition Universe.h:839
#define TIME_ACCELERATION_FACTOR_MAX
Definition Universe.h:166
#define TIME_ACCELERATION_FACTOR_MIN
Definition Universe.h:164
void setGamePaused:(BOOL value)
BOOL setDisplayWidth:Height:Refresh:(unsigned int d_width,[Height] unsigned int d_height,[Refresh] unsigned int d_refresh)
void exitAppWithContext:(NSString *context)
void setMouseInteractionModeForFlight()
void pauseFullScreenModeToPerform:onTarget:(SEL selector,[onTarget] id target)
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)
BOOL checkKeyPress:(NSArray *key_def)
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:191
Entity * sortedEntities[UNIVERSE_MAX_ENTITIES+1]
Definition Universe.h:190
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()