oolite/PlayerEntity_StickMapper.m
2005-10-01 16:32:46 +00:00

364 lines
12 KiB
Objective-C

/* */
// PlayerEntity_StickMapper.m
//
// Created for the Oolite-Linux project, but portable to other archs.
//
// Dylan Smith, 2005-09-24
//
// This category adds the GUI to handle player assignments of joystick
// things (axes, buttons) to game functions.
//
// oolite: (c) 2004 Giles C Williams.
// This work is licensed under the Creative Commons Attribution NonCommercial
// ShareAlike license.
//
#import "PlayerEntity_StickMapper.h"
#import "JoystickHandler.h"
@implementation PlayerEntity (StickMapper)
- (void) setGuiToStickMapperScreen
{
GuiDisplayGen *gui=[universe gui];
NSArray *stickList=[stickHandler listSticks];
int i;
int tabStop[GUI_MAX_COLUMNS];
tabStop[0]=50;
tabStop[1]=210;
tabStop[2]=320;
[gui setTabStops: tabStop];
gui_screen=GUI_SCREEN_STICKMAPPER;
[gui clear];
[gui setTitle:[NSString stringWithFormat:@"Configure Joysticks"]];
for(i=0; i < [stickList count]; i++)
{
[gui setArray: [NSArray arrayWithObjects:
[NSString stringWithFormat: @"Stick %d", i+1],
[stickList objectAtIndex: i], nil]
forRow: i + STICKNAME_ROW];
}
[self displayFunctionList: gui];
[gui setArray: [NSArray arrayWithObjects:
[NSString stringWithString: @"Select a function and press Enter to modify or 'u' to unset."], nil]
forRow: INSTRUCT_ROW];
[gui setSelectedRow: selFunctionIdx + FUNCSTART_ROW];
[[universe gameView] supressKeysUntilKeyUp];
}
- (void) stickMapperInputHandler: (GuiDisplayGen *)gui
view: (MyOpenGLView *)gameView
{
// Don't do anything if the user is supposed to be selecting
// a function - other than look for Escape.
if(waitingForStickCallback)
{
if([gameView isDown: 27])
{
[stickHandler clearCallback];
[gui setArray: [NSArray arrayWithObjects:
[NSString stringWithString: @"Function setting aborted."], nil]
forRow: INSTRUCT_ROW];
waitingForStickCallback=NO;
}
// Break out now.
return;
}
[self handleGUIUpDownArrowKeys: gui: gameView];
if([gameView isDown: 13])
{
selFunctionIdx=[gui selectedRow]-FUNCSTART_ROW;
NSDictionary *entry=[stickFunctions objectAtIndex: selFunctionIdx];
int hw=[(NSNumber *)[entry objectForKey: KEY_ALLOWABLE] intValue];
[stickHandler setCallback: @selector(updateFunction:)
object: self
hardware: hw];
// Print instructions
NSString *instructions;
switch(hw)
{
case HW_AXIS:
instructions=[NSString stringWithString:
@"Fully deflect the axis you want to use for this function. Esc aborts."];
break;
case HW_BUTTON:
instructions=[NSString stringWithString:
@"Press the button you want to use for this function. Esc aborts."];
break;
default:
instructions=[NSString stringWithString:
@"Press the button or deflect the axis you want to use for this function."];
}
[gui setArray: [NSArray arrayWithObjects: instructions, nil] forRow: INSTRUCT_ROW];
waitingForStickCallback=YES;
}
if([gameView isDown: 'u'])
{
[self removeFunction: [gui selectedRow]-FUNCSTART_ROW];
}
}
// Callback function, called by JoystickHandler when the callback
// is set. The dictionary contains the thing that was pressed/moved.
- (void) updateFunction: (NSDictionary *)hwDict
{
waitingForStickCallback=NO;
// Right time and the right place?
if(gui_screen != GUI_SCREEN_STICKMAPPER)
{
NSLog(@"updateFunction: Oops, we weren't expecting that callback");
return;
}
// What moved?
int function;
NSDictionary *entry=[stickFunctions objectAtIndex: selFunctionIdx];
if([(NSNumber *)[hwDict objectForKey: STICK_ISAXIS] boolValue] == YES)
{
function=[(NSNumber *)[entry objectForKey: KEY_AXISFN] intValue];
}
else
{
function=[(NSNumber *)[entry objectForKey: KEY_BUTTONFN] intValue];
}
[stickHandler setFunction: function withDict: hwDict];
[stickHandler saveStickSettings];
// Update the GUI (this will refresh the function list).
[self setGuiToStickMapperScreen];
}
- (void) removeFunction: (int)idx
{
selFunctionIdx=idx;
NSDictionary *entry=[stickFunctions objectAtIndex: idx];
NSNumber *butfunc=[entry objectForKey: KEY_BUTTONFN];
NSNumber *axfunc=[entry objectForKey: KEY_AXISFN];
// Some things can have either axis or buttons - make sure we clear
// both!
if(butfunc)
{
[stickHandler unsetButtonFunction: [butfunc intValue]];
}
if(axfunc)
{
[stickHandler unsetAxisFunction: [axfunc intValue]];
}
[stickHandler saveStickSettings];
[self setGuiToStickMapperScreen];
}
- (void) displayFunctionList: (GuiDisplayGen *)gui
{
int i;
[gui setColor: [NSColor greenColor] forRow: HEADINGROW];
[gui setArray: [NSArray arrayWithObjects:
@"Function", @"Assigned to", @"Type", nil]
forRow: HEADINGROW];
if(!stickFunctions)
{
stickFunctions=[self getStickFunctionList];
}
NSDictionary *assignedAxes=[stickHandler getAxisFunctions];
NSDictionary *assignedButs=[stickHandler getButtonFunctions];
for(i=0; i < [stickFunctions count]; i++)
{
NSString *allowedThings;
NSString *assignment;
NSDictionary *entry=[stickFunctions objectAtIndex: i];
NSString *axFuncKey=[(NSNumber *)[entry objectForKey: KEY_AXISFN] stringValue];
NSString *butFuncKey=[(NSNumber *)[entry objectForKey: KEY_BUTTONFN] stringValue];
int allowable=[(NSNumber *)[entry objectForKey: KEY_ALLOWABLE] intValue];
switch(allowable)
{
case HW_AXIS:
allowedThings=[NSString stringWithString: @"Axis"];
assignment=[self describeStickDict:
[assignedAxes objectForKey: axFuncKey]];
break;
case HW_BUTTON:
allowedThings=[NSString stringWithString: @"Button"];
assignment=[self describeStickDict:
[assignedButs objectForKey: butFuncKey]];
break;
default:
allowedThings=[NSString stringWithString: @"Axis/Button"];
// axis has priority
assignment=[self describeStickDict:
[assignedAxes objectForKey: axFuncKey]];
if(!assignment)
assignment=[self describeStickDict:
[assignedButs objectForKey: butFuncKey]];
}
// Find out what's assigned for this function currently.
if(!assignment)
assignment=[NSString stringWithString: @" - "];
[gui setArray: [NSArray arrayWithObjects:
[entry objectForKey: KEY_GUIDESC], assignment, allowedThings, nil]
forRow: i + FUNCSTART_ROW];
[gui setKey: GUI_KEY_OK forRow: i + FUNCSTART_ROW];
}
[gui setSelectableRange: NSMakeRange(FUNCSTART_ROW, i + FUNCSTART_ROW - 1)];
}
- (NSString *) describeStickDict: (NSDictionary *)stickDict
{
NSString *desc=nil;
if(stickDict)
{
int thingNumber=[(NSNumber *)[stickDict objectForKey: STICK_AXBUT]
intValue];
int stickNumber=[(NSNumber *)[stickDict objectForKey: STICK_NUMBER]
intValue];
// Button or axis?
if([(NSNumber *)[stickDict objectForKey: STICK_ISAXIS] boolValue])
{
desc=[NSString stringWithFormat: @"Stick %d axis %d",
stickNumber+1, thingNumber+1];
}
else
{
desc=[NSString stringWithFormat: @"Stick %d button %d",
stickNumber+1, thingNumber+1];
}
}
return desc;
}
- (NSString *)hwToString: (int)hwFlags
{
NSString *hwString;
switch(hwFlags)
{
case HW_AXIS:
hwString=[NSString stringWithString: @"axis"];
break;
case HW_BUTTON:
hwString=[NSString stringWithString: @"button"];
break;
default:
hwString=[NSString stringWithString: @"axis/button"];
}
return hwString;
}
// TODO:
// FUTURE: This data could be put into a plist (i18n or just modifiable by
// the user). It is otherwise an ugly method, but it'll do for testing.
- (NSArray *)getStickFunctionList
{
NSMutableArray *funcList=[[NSMutableArray alloc] init];
[funcList addObject:
[self makeStickGuiDict: @"Roll"
allowable: HW_AXIS
axisfn: AXIS_ROLL
butfn: STICK_NOFUNCTION]];
[funcList addObject:
[self makeStickGuiDict: @"Pitch"
allowable: HW_AXIS
axisfn: AXIS_PITCH
butfn: STICK_NOFUNCTION]];
[funcList addObject:
[self makeStickGuiDict: @"Increase thrust"
allowable: HW_AXIS|HW_BUTTON
axisfn: AXIS_THRUST
butfn: BUTTON_INCTHRUST]];
[funcList addObject:
[self makeStickGuiDict: @"Decrease thrust"
allowable: HW_AXIS|HW_BUTTON
axisfn: AXIS_THRUST
butfn: BUTTON_DECTHRUST]];
[funcList addObject:
[self makeStickGuiDict: @"Primary weapon"
allowable: HW_BUTTON
axisfn: STICK_NOFUNCTION
butfn: BUTTON_FIRE]];
[funcList addObject:
[self makeStickGuiDict: @"Secondary weapon"
allowable: HW_BUTTON
axisfn: STICK_NOFUNCTION
butfn: BUTTON_LAUNCHMISSILE]];
[funcList addObject:
[self makeStickGuiDict: @"Arm secondary"
allowable: HW_BUTTON
axisfn: STICK_NOFUNCTION
butfn: BUTTON_ARMMISSILE]];
[funcList addObject:
[self makeStickGuiDict: @"Disarm secondary"
allowable: HW_BUTTON
axisfn: STICK_NOFUNCTION
butfn: BUTTON_UNARM]];
[funcList addObject:
[self makeStickGuiDict: @"Cycle secondary"
allowable: HW_BUTTON
axisfn: STICK_NOFUNCTION
butfn: BUTTON_CYCLEMISSILE]];
[funcList addObject:
[self makeStickGuiDict: @"ECM"
allowable: HW_BUTTON
axisfn: STICK_NOFUNCTION
butfn: BUTTON_ECM]];
[funcList addObject:
[self makeStickGuiDict: @"Toggle ID"
allowable: HW_BUTTON
axisfn: STICK_NOFUNCTION
butfn: BUTTON_ID]];
[funcList addObject:
[self makeStickGuiDict: @"Fuel Injection"
allowable: HW_BUTTON
axisfn: STICK_NOFUNCTION
butfn: BUTTON_FUELINJECT]];
[funcList addObject:
[self makeStickGuiDict: @"Hyperspeed"
allowable: HW_BUTTON
axisfn: STICK_NOFUNCTION
butfn: BUTTON_HYPERSPEED]];
[funcList addObject:
[self makeStickGuiDict: @"Roll/pitch precision toggle"
allowable: HW_BUTTON
axisfn: STICK_NOFUNCTION
butfn: BUTTON_PRECISION]];
return funcList;
}
- (NSDictionary *)makeStickGuiDict: (NSString *)what
allowable: (int)allowable
axisfn: (int)axisfn
butfn: (int)butfn
{
NSMutableDictionary *guiDict=[[NSMutableDictionary alloc] init];
[guiDict setObject: what forKey: KEY_GUIDESC];
[guiDict setObject: [NSNumber numberWithInt: allowable]
forKey: KEY_ALLOWABLE];
if(axisfn >= 0)
[guiDict setObject: [NSNumber numberWithInt: axisfn]
forKey: KEY_AXISFN];
if(butfn >= 0)
[guiDict setObject: [NSNumber numberWithInt: butfn]
forKey: KEY_BUTTONFN];
return guiDict;
}
@end