Autopilot controls revamp, as discussed.

- c now tries to dock either at the players' current target, a nearby station, or the system main station.
 - Shift-C does the same, except attempts a fast-dock if the station allows it.
Added a new key 'allowsFastDocking'. Defaults to YES for the system main station, and NO to all other stations.
 - Shift-D is no longer used.
Also, autopilot will no longer engage on Condition Red.


git-svn-id: http://svn.berlios.de/svnroot/repos/oolite-linux/trunk@3783 127b21dd-08f5-0310-b4b7-95ae10353056
This commit is contained in:
Michael Werle 2010-10-28 19:55:35 +00:00
parent dc31b510f5
commit c085bcdd2b
9 changed files with 158 additions and 119 deletions

View File

@ -432,6 +432,8 @@
"autopilot-cannot-dock-with-target" = "Target is not capable of autopilot-docking.";
"autopilot-target-docking-instructions-denied" = "Target has denied broadcast of docking instructions.";
"autopilot-denied" = "Station refuses to issue docking instructions.";
"autopilot-multiple-targets" = "Multiple autopilot targets in vicinity.";
"autopilot-red-alert" = "Red Alert! Cannot engage autopilot.";
"witch-to-@-in-f-seconds" = "Witchspace to %@ in %.0f s.";
"witch-blocked-by-@" = "Witchspace jump aborted (too close to %@.)";
"witch-user-abort" = "Witchspace jump aborted.";

View File

@ -35,8 +35,7 @@
key_rotate_cargo = "R";
key_autopilot = "c";
key_autopilot_target = "C";
key_autodock = "D";
key_autodock = "C";
key_docking_clearance_request = "L";
key_snapshot = "*";

View File

@ -75,7 +75,6 @@ static BOOL cloak_pressed;
static BOOL rotateCargo_pressed;
static BOOL autopilot_key_pressed;
static BOOL fast_autopilot_key_pressed;
static BOOL target_autopilot_key_pressed;
#if DOCKING_CLEARANCE_ENABLED
static BOOL docking_clearance_request_key_pressed;
#endif
@ -136,6 +135,8 @@ static NSTimeInterval time_last_frame;
- (void) handleMissionCallback;
- (void) switchToThisView:(OOViewID) viewDirection;
- (void) handleAutopilotOn:(BOOL)fastDocking;
@end
@ -224,8 +225,7 @@ static NSTimeInterval time_last_frame;
LOAD_KEY_SETTING(key_rotate_cargo, 'R' );
LOAD_KEY_SETTING(key_autopilot, 'c' );
LOAD_KEY_SETTING(key_autopilot_target, 'C' );
LOAD_KEY_SETTING(key_autodock, 'D' );
LOAD_KEY_SETTING(key_autodock, 'C' );
#if DOCKING_CLEARANCE_ENABLED
LOAD_KEY_SETTING(key_docking_clearance_request, 'L' );
#endif
@ -644,8 +644,6 @@ static NSTimeInterval time_last_frame;
if (![UNIVERSE displayCursor])
{
BOOL isOkayToUseAutopilot = legalStatus <= 50; // used for C, shift-C, & shift-D (same condition handled inside station code for docking clearance)
exceptionContext = @"afterburner";
if ((joyButtonState[BUTTON_FUELINJECT] || [gameView isDown:key_inject_fuel]) &&
[self hasFuelInjection] &&
@ -997,29 +995,9 @@ static NSTimeInterval time_last_frame;
// autopilot 'c'
if ([gameView isDown:key_autopilot] || joyButtonState[BUTTON_DOCKCPU]) // look for the 'c' key
{
if ([self hasDockingComputer] && !autopilot_key_pressed) // look for the 'c' key
if ([self hasDockingComputer] && (!autopilot_key_pressed))
{
BOOL isUsingDockingAI = [[shipAI name] isEqual: PLAYER_DOCKING_AI_NAME];
if (isUsingDockingAI)
{
if ([self checkForAegis] != AEGIS_IN_DOCKING_RANGE)
{
isOkayToUseAutopilot = NO;
[self playAutopilotOutOfRange];
[UNIVERSE addMessage:DESC(@"autopilot-out-of-range") forCount:4.5];
}
else
{
if (!isOkayToUseAutopilot) [UNIVERSE addMessage:DESC(@"autopilot-denied") forCount:4.5];
}
}
if (isOkayToUseAutopilot)
{
[self engageAutopilotToStation:[UNIVERSE station]];
[UNIVERSE addMessage:DESC(@"autopilot-on") forCount:4.5];
}
[self handleAutopilotOn:false];
}
autopilot_key_pressed = YES;
}
@ -1027,84 +1005,12 @@ static NSTimeInterval time_last_frame;
autopilot_key_pressed = NO;
exceptionContext = @"autopilot shift-C";
// autopilot 'C' - dock with target
if ([gameView isDown:key_autopilot_target]) // look for the 'C' key
// autopilot 'C' - fast-autopilot
if ([gameView isDown:key_autodock] || joyButtonState[BUTTON_DOCKCPUFAST]) // look for the 'C' key
{
if ([self hasDockingComputer] && (!target_autopilot_key_pressed))
if ([self hasDockingComputer] && (!fast_autopilot_key_pressed))
{
StationEntity* primeTarget = [self primaryTarget];
BOOL primeTargetIsHostile = [self hasHostileTarget];
isOkayToUseAutopilot = isOkayToUseAutopilot && primeTarget == [UNIVERSE station];
if (primeTarget != nil && [primeTarget isStation] &&
(!primeTargetIsHostile || isOkayToUseAutopilot))
{
[self engageAutopilotToStation:primeTarget];
[UNIVERSE addMessage:DESC(@"autopilot-on") forCount:4.5];
}
else
{
[self playAutopilotCannotDockWithTarget];
if (primeTargetIsHostile && [primeTarget isStation])
{
[UNIVERSE addMessage:DESC(@"autopilot-target-docking-instructions-denied") forCount:4.5];
}
else
{
[UNIVERSE addMessage:DESC(@"autopilot-cannot-dock-with-target") forCount:4.5];
}
}
}
target_autopilot_key_pressed = YES;
}
else
target_autopilot_key_pressed = NO;
exceptionContext = @"autopilot shift-D";
// autopilot 'D'
if ([gameView isDown:key_autodock] || joyButtonState[BUTTON_DOCKCPUFAST]) // look for the 'D' key
{
if ([self hasDockingComputer] && (!fast_autopilot_key_pressed)) // look for the 'D' key
{
if ([self checkForAegis] == AEGIS_IN_DOCKING_RANGE)
{
StationEntity *the_station = [UNIVERSE station];
if (the_station)
{
if (!isOkayToUseAutopilot)
{
[self setStatus:STATUS_AUTOPILOT_ENGAGED];
[self interpretAIMessage:@"DOCKING_REFUSED"];
}
else
{
if (legalStatus > 0)
{
// there's a slight chance you'll be fined for your past offences when autodocking
int fine_chance = ranrot_rand() & 0x03ff; // 0..1023
int government = 1 + [[UNIVERSE currentSystemData] oo_intForKey:KEY_GOVERNMENT]; // 1..8
if ([UNIVERSE inInterstellarSpace]) government = 2; // equivalent to Feudal. I'm assuming any station in interstellar space is military. -- Ahruman 2008-05-29
fine_chance /= government;
if (fine_chance < legalStatus)
{
[self markForFines];
}
}
#if DOCKING_CLEARANCE_ENABLED
[self setDockingClearanceStatus:DOCKING_CLEARANCE_STATUS_GRANTED];
#endif
ship_clock_adjust = 1200.0; // 20 minutes penalty to enter dock
ident_engaged = NO;
[self safeAllMissiles];
[UNIVERSE setViewDirection:VIEW_FORWARD];
[self enterDock:the_station];
}
}
}
else
{
[self playAutopilotOutOfRange];
[UNIVERSE addMessage:DESC(@"autopilot-out-of-range") forCount:4.5];
}
[self handleAutopilotOn:true];
}
fast_autopilot_key_pressed = YES;
}
@ -3107,19 +3013,7 @@ static BOOL toggling_music;
}
else
autopilot_key_pressed = NO;
if ([gameView isDown:key_autopilot_target]) // look for the 'C' key
{
if ([self hasDockingComputer] && !target_autopilot_key_pressed) // look for the 'C' key
{
[self disengageAutopilot];
[UNIVERSE addMessage:DESC(@"autopilot-off") forCount:4.5];
}
target_autopilot_key_pressed = YES;
}
else
target_autopilot_key_pressed = NO;
if (([gameView isDown:key_docking_music])) // look for the 's' key
{
if (!toggling_music)
@ -3370,4 +3264,114 @@ static BOOL toggling_music;
[self currentWeaponStats];
}
// Called on c or Shift-C
- (void) handleAutopilotOn:(BOOL)fastDocking
{
BOOL isOkayToUseAutopilot = NO;
Entity *target = nil;
// Check alert condition - on red alert, abort
isOkayToUseAutopilot = [self alertCondition] != ALERT_CONDITION_RED;
if( !isOkayToUseAutopilot )
{
[self playAutopilotCannotDockWithTarget];
[UNIVERSE addMessage:DESC(@"autopilot-red-alert") forCount:4.5];
goto abort;
}
// Check if current target is dockable
target = [self primaryTarget];
isOkayToUseAutopilot = target && [target isStation] && [target isKindOfClass:[StationEntity class]];
// Otherwise check for nearby dockables
if( !isOkayToUseAutopilot )
{
Universe *uni = UNIVERSE;
Entity **entities = uni->sortedEntities; // grab the public sorted list
int nStations = 0;
int i;
for( i = 0; i < uni->n_entities && nStations < 2; i++ )
{
if( entities[i]->isStation && [entities[i] isKindOfClass:[StationEntity class]] &&
entities[i]->zero_distance <= SCANNER_MAX_RANGE2 )
{
nStations++;
target = entities[i];
}
}
// If we found no targets, check for main station Aegis.
// If we found one target, dock with it.
// If we found multiple targets, abort.
switch(nStations)
{
case 0:
if ([self checkForAegis] == AEGIS_IN_DOCKING_RANGE)
{
isOkayToUseAutopilot = YES;
target = [UNIVERSE station];
}
else
{
[self playAutopilotOutOfRange];
[UNIVERSE addMessage:DESC(@"autopilot-out-of-range") forCount:4.5];
goto abort;
}
break;
case 1:
isOkayToUseAutopilot = YES;
break;
default:
[self playAutopilotCannotDockWithTarget];
[UNIVERSE addMessage:DESC(@"autopilot-multiple-targets") forCount:4.5];
goto abort;
}
}
// We found a dockable, check whether we can dock with it
StationEntity *ts = (StationEntity*)target;
// Deny docking if player is fugitive or station is hostile
if( legalStatus > 50 || [ts isHostileTo:self] )
{
[self playAutopilotCannotDockWithTarget];
if(ts == [UNIVERSE station] )
[UNIVERSE addMessage:DESC(@"autopilot-denied") forCount:4.5];
else
[UNIVERSE addMessage:DESC(@"autopilot-target-docking-instructions-denied") forCount:4.5];
}
// If we're fast-docking, perform the docking logic
else if( fastDocking && [ts allowsFastDocking] )
{
if (legalStatus > 0)
{
// there's a slight chance you'll be fined for your past offences when autodocking
int fine_chance = ranrot_rand() & 0x03ff; // 0..1023
int government = 1 + [[UNIVERSE currentSystemData] oo_intForKey:KEY_GOVERNMENT]; // 1..8
if ([UNIVERSE inInterstellarSpace]) government = 2; // equivalent to Feudal. I'm assuming any station in interstellar space is military. -- Ahruman 2008-05-29
fine_chance /= government;
if (fine_chance < legalStatus)
{
[self markForFines];
}
}
#if DOCKING_CLEARANCE_ENABLED
[self setDockingClearanceStatus:DOCKING_CLEARANCE_STATUS_GRANTED];
#endif
ship_clock_adjust = 1200.0; // 20 minutes penalty to enter dock
ident_engaged = NO;
[self safeAllMissiles];
[UNIVERSE setViewDirection:VIEW_FORWARD];
[self enterDock:ts];
}
// Standard docking - engage autopilot
else
{
[self engageAutopilotToStation:ts];
[UNIVERSE addMessage:DESC(@"autopilot-on") forCount:4.5];
}
abort:
// Clean-up code, if any
return;
}
@end

View File

@ -582,6 +582,7 @@ MA 02110-1301, USA.
- (BOOL)isUnpiloted; // Has unpiloted = yes in its shipdata.plist entry
- (BOOL) hasHostileTarget;
- (BOOL) isHostileTo:(Entity *)entity;
- (GLfloat) weaponRange;
- (void) setWeaponRange:(GLfloat) value;

View File

@ -4731,6 +4731,10 @@ static GLfloat scripted_color[4] = { 0.0, 0.0, 0.0, 0.0}; // to be defined by s
return IsBehaviourHostile(behaviour);
}
- (BOOL) isHostileTo:(Entity *)entity
{
return ([self hasHostileTarget] && [self primaryTarget] == entity);
}
- (GLfloat) weaponRange
{

View File

@ -98,7 +98,7 @@ typedef enum
BOOL requiresDockingClearance;
#endif
BOOL interstellarUndockingAllowed;
BOOL allowsFastDocking;
}
- (void) setDockingPortModel:(ShipEntity*) dock_model :(Vector) dock_pos :(Quaternion) dock_q;
@ -199,6 +199,9 @@ typedef enum
- (void) setRequiresDockingClearance:(BOOL)newValue;
#endif
- (BOOL) allowsFastDocking;
- (void) setAllowsFastDocking:(BOOL)newValue;
- (NSString *) dockingPatternModelFileName;
- (NSString *) marketOverrideName;
- (BOOL) isRotatingStation;

View File

@ -809,6 +809,7 @@ static NSDictionary* instructions(int station_id, Vector coords, float speed, fl
requiresDockingClearance = [dict oo_boolForKey:@"requires_docking_clearance" defaultValue:
universalInfo != nil ? [universalInfo oo_boolForKey:@"stations_require_docking_clearance" defaultValue:NO] : NO];
#endif
allowsFastDocking = [dict oo_boolForKey:@"allows_fast_docking" defaultValue:NO];
NSString *defaultBreakPattern = [universalInfo oo_stringForKey:@"default_dockpattern_model" defaultValue:[universalInfo oo_stringForKey:@"default_breakpattern_model"]];
if (defaultBreakPattern == nil) defaultBreakPattern = @"oolite-tunnel.dat";
@ -2168,6 +2169,16 @@ static NSDictionary* instructions(int station_id, Vector coords, float speed, fl
}
#endif
- (BOOL) allowsFastDocking
{
return allowsFastDocking;
}
- (void) setAllowsFastDocking:(BOOL)newValue
{
allowsFastDocking = !!newValue; // Ensure yes or no
}
- (BOOL) isRotatingStation
{

View File

@ -86,6 +86,7 @@ enum
#if DOCKING_CLEARANCE_ENABLED
kStation_requiresDockingClearance,
#endif
kStation_allowsFastDocking,
kStation_suppressArrivalReports,
};
@ -99,6 +100,7 @@ static JSPropertySpec sStationProperties[] =
#if DOCKING_CLEARANCE_ENABLED
{ "requiresDockingClearance", kStation_requiresDockingClearance, JSPROP_PERMANENT | JSPROP_ENUMERATE },
#endif
{ "allowsFastDocking", kStation_allowsFastDocking, JSPROP_PERMANENT | JSPROP_ENUMERATE },
{ "dockedContractors", kStation_dockedContractors, JSPROP_PERMANENT | JSPROP_ENUMERATE | JSPROP_READONLY },
{ "dockedPolice", kStation_dockedPolice, JSPROP_PERMANENT | JSPROP_ENUMERATE | JSPROP_READONLY },
{ "dockedDefenders", kStation_dockedDefenders, JSPROP_PERMANENT | JSPROP_ENUMERATE | JSPROP_READONLY },
@ -201,6 +203,10 @@ static JSBool StationGetProperty(JSContext *context, JSObject *this, jsval name,
break;
#endif
case kStation_allowsFastDocking:
*outValue = BOOLToJSVal([entity allowsFastDocking]);
break;
case kStation_dockedContractors:
*outValue = INT_TO_JSVAL([entity dockedContractors]);
break;
@ -276,6 +282,14 @@ static JSBool StationSetProperty(JSContext *context, JSObject *this, jsval name,
break;
#endif
case kStation_allowsFastDocking:
if (JS_ValueToBoolean(context, *value, &bValue))
{
[entity setAllowsFastDocking:bValue];
OK = YES;
}
break;
case kStation_suppressArrivalReports:
if (JS_ValueToBoolean(context, *value, &bValue))
{

View File

@ -970,6 +970,7 @@ static OOComparisonResult comparePrice(id dict1, id dict2, void * context);
[a_station setEquivalentTechLevel:techlevel];
[self addEntity:a_station]; // STATUS_IN_FLIGHT, AI state GLOBAL
[a_station setStatus:STATUS_ACTIVE]; // For backward compatibility. Might not be needed.
[a_station setAllowsFastDocking:true]; // Main stations always allow fast docking.
}
cachedSun = a_sun;