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