55@interface AI (OOPrivate)
 
   58- (void) performDeferredCall:(
SEL)selector withObject:(
id)object afterDelay:(NSTimeInterval)delay;
 
   59+ (void) deferredCallTrampolineWithInfo:(NSValue *)info;
 
   64- (void) directSetStateMachine:(NSDictionary *)newSM name:(NSString *)name;
 
   65- (void) directSetState:(NSString *)state;
 
   68- (NSDictionary *) loadStateMachine:(NSString *)smName jsName:(NSString *)script;
 
   69- (NSDictionary *) cleanHandlers:(NSDictionary *)handlers forState:(NSString *)stateKey stateMachine:(NSString *)smName;
 
   70- (NSArray *) cleanActions:(NSArray *)actions forHandler:(NSString *)handlerKey state:(NSString *)stateKey stateMachine:(NSString *)smName;
 
   76extern void GenerateGraphVizForAIStateMachine(NSDictionary *stateMachine, NSString *name);
 
   90- (id) initWithStateMachine:(NSDictionary *)stateMachine
 
   92                      state:(NSString *)state
 
   93            pendingMessages:(NSSet *)pendingMessages
 
   94                                     jsScript:(NSString *)script;
 
   96- (NSDictionary *) stateMachine;
 
   99- (NSSet *) pendingMessages;
 
  100- (NSString *) jsScript;
 
  121        return @"<no AI running>";
 
 
  128    if ((
self = [super 
init]))
 
 
  140- (id) initWithStateMachine:(NSString *)smName andState:(NSString *)stateName
 
  142    if ((
self = [
self init]))
 
   140- (id) initWithStateMachine:(NSString *)smName andState:(NSString *)stateName {
…}
  
  174    return [
NSString stringWithFormat:@"\"%@\" in state: \"%@\" for %@", stateMachineName, currentState, ownerDesc];
 
 
  180    return [
NSString stringWithFormat:@"%@:%@ / %@", stateMachineName, currentState, [stateMachine objectForKey:@"jsScript"]];
 
 
  211        NSString *trailer = stackDump ? 
@" -- stack:" : 
@".";
 
  218            NSUInteger 
count = [aiStack count];
 
  222                OOLog(
@"ai.error.stackOverflow.dump", 
@"%3lu: %@: %@", 
count, [preservedMachine 
name], [preservedMachine 
state]);
 
 
  245                    format:@"AI stack overflow for %@", _owner];
 
  249                                                   initWithStateMachine:stateMachine
 
  250                                                                   name:stateMachineName
 
  252                                                        pendingMessages:pendingMessages
 
  253                                                                                                    jsScript:[stateMachine objectForKey:@"jsScript"]];
 
  256    if ([[
self owner] reportAIMessages])  
OOLog(
@"ai.stack.push", 
@"Pushing state machine for %@", 
self);
 
  259    [aiStack addObject:preservedMachine];  
 
 
  272    if ([[
self owner] reportAIMessages])  
OOLog(
@"ai.stack.pop", 
@"Popping previous state machine for %@", 
self);
 
  283    [pendingMessages release];
 
  286    [aiStack removeLastObject];  
 
 
  292    return [aiStack count] != 0;
 
 
  296- (void) exitStateMachineWithMessage:(NSString *)message
 
  301        if (message == 
nil)  message = 
@"RESTARTED";
 
   296- (void) exitStateMachineWithMessage:(NSString *)message {
…}
  
  307- (void) setStateMachine:(NSString *)smName withJSScript:(NSString *)script
 
   307- (void) setStateMachine:(NSString *)smName withJSScript:(NSString *)script {
…}
  
  334- (void) setState:(NSString *) stateName
 
   334- (void) setState:(NSString *) stateName {
…}
  
  352- (void) setStateMachine:(NSString *)smName afterDelay:(NSTimeInterval)delay
 
   352- (void) setStateMachine:(NSString *)smName afterDelay:(NSTimeInterval)delay {
…}
  
  358- (void) setState:(NSString *)stateName afterDelay:(NSTimeInterval)delay
 
   358- (void) setState:(NSString *)stateName afterDelay:(NSTimeInterval)delay {
…}
  
  366    return [[stateMachineName retain] autorelease];
 
 
  372    return [stateMachine objectForKey:@"jsScript"];
 
 
  378    return [[currentState retain] autorelease];
 
 
  384    return [aiStack count];
 
 
  404- (void) reactToMessage:(NSString *) message context:(NSString *)debugContext
 
  407    NSArray         *actions = 
nil;
 
  408    NSDictionary    *messagesForState = 
nil;
 
  410    static unsigned recursionLimiter = 0;
 
  422    if (debugContext == 
nil)  debugContext = 
@"unspecified";
 
  427        .aiName = [[stateMachineName retain] autorelease],
 
  428        .state = [[currentState retain] autorelease],
 
  430        .context = debugContext
 
  443        OOLogERR(
@"ai.error.recursion", 
@"AI dispatch: hit stack depth limit in AI %@, state %@ handling message %@ in context \"%@\
", aborting.", 
stateMachineName, 
currentState, message, debugContext);
 
  448        while (stack != NULL)
 
  461    messagesForState = [stateMachine objectForKey:currentState];
 
  462    if (messagesForState == 
nil)  
return;
 
  474    if ([actions 
count] > 0)
 
  479            for (i = 0; i < [
actions count]; i++)
 
  484        @catch (NSException *exception)
 
  495            if ([
owner respondsToSelector:
@selector(interpretAIMessage:)])
 
  497                [
owner performSelector:@selector(interpretAIMessage:) withObject:message];
 
   404- (void) reactToMessage:(NSString *) message context:(NSString *)debugContext {
…}
  
  510- (void) takeAction:(NSString *)action
 
  518        OOLog(
@"ai.takeAction", 
@"%@ to take action %@", 
ownerDesc, action);
 
  524    NSUInteger tokenCount = [
tokens count];
 
  528        NSString *selectorStr = [
tokens objectAtIndex:0];
 
  532            NSString *dataString = 
nil;
 
  536                dataString = [
tokens objectAtIndex:1];
 
  538            else if ([tokens 
count] > 1)
 
  540                dataString = [[
tokens subarrayWithRange:NSMakeRange(1, tokenCount - 1)] componentsJoinedByString:@" "];
 
  543            SEL selector = NSSelectorFromString(selectorStr);
 
  544            if ([
owner respondsToSelector:selector])
 
  546                if (dataString != 
nil)  [
owner performSelector:selector withObject:dataString];
 
  547                else  [
owner performSelector:selector];
 
  556            OOLog(
@"ai.takeAction.orphaned", 
@"***** AI %@, trying to perform %@, is orphaned (no owner)", 
stateMachineName, selectorStr);
 
  562        if (report)  
OOLog(
@"ai.takeAction.noAction", 
@"DEBUG: - no action '%@'", action);
 
   510- (void) takeAction:(NSString *)action {
…}
  
  577    NSArray         *ms_list = 
nil;
 
  586        ms_list = [pendingMessages allObjects];
 
  587        [pendingMessages removeAllObjects];
 
  592        for (i = 0; i < [
ms_list count]; i++)
 
 
  600- (void) message:(NSString *)ms
 
  607        OOLogERR(
@"ai.message.failed.overflow", 
@"AI message \"%@\
" received by '%@' AI while pending messages stack full; message discarded. Pending messages:\n%@", ms, 
ownerDesc, 
pendingMessages);
 
  615        [pendingMessages addObject:ms];
 
   600- (void) message:(NSString *)ms {
…}
  
  620- (void) dropMessage:(NSString *)ms
 
  622    [pendingMessages removeObject:ms];
 
   620- (void) dropMessage:(NSString *)ms {
…}
  
  630        return [[pendingMessages copy] autorelease];
 
 
  641    NSArray             *sortedMessages = 
nil;
 
  642    NSString            *displayMessages = 
nil;
 
  646        sortedMessages = [[pendingMessages allObjects] sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];
 
  647        displayMessages = [
sortedMessages componentsJoinedByString:@", "];
 
  651        displayMessages = 
@"none";
 
 
  687    [aiStack removeAllObjects];
 
 
  693    [aiStack removeAllObjects];
 
  694    [pendingMessages removeAllObjects];
 
 
  717@implementation AI (OOPrivate)
 
  719- (void)performDeferredCall:(
SEL)selector withObject:(
id)object afterDelay:(NSTimeInterval)delay
 
  724    if (selector != NULL)
 
  726        infoStruct.
ai = [
self retain];
 
  730        info = [[
NSValue alloc] initWithBytes:&infoStruct objCType:@encode(OOAIDeferredCallTrampolineInfo)];
 
  732        [[
AI class] performSelector:@selector(deferredCallTrampolineWithInfo:)
 
   719- (void)performDeferredCall:(
SEL)selector withObject:(
id)object afterDelay:(NSTimeInterval)delay {
…}
  
  740+ (void)deferredCallTrampolineWithInfo:(NSValue *)info
 
  747        [
info getValue:&infoStruct];
 
  749        [
infoStruct.
ai performSelector:infoStruct.selector withObject:infoStruct.parameter];
 
   740+ (void)deferredCallTrampolineWithInfo:(NSValue *)info {
…}
  
  761    if ([owner isPlayer])
 
  763        ownerDesc = 
@"player autopilot";
 
  765    else if (owner != 
nil)
 
  771        ownerDesc = 
@"no owner";
 
 
  776- (void) directSetStateMachine:(NSDictionary *)newSM name:(NSString *)name
 
  778    if (stateMachine != newSM)
 
  781        stateMachine = [
newSM copy];
 
  783    if (stateMachineName != name)
 
  786        stateMachineName = [
name copy];
 
   776- (void) directSetStateMachine:(NSDictionary *)newSM name:(NSString *)name {
…}
  
  791- (void) directSetState:(NSString *)state
 
  793    if (currentState != state)
 
  796        currentState = [
state copy];
 
   791- (void) directSetState:(NSString *)state {
…}
  
  801- (NSDictionary *) loadStateMachine:(NSString *)smName jsName:(NSString *)script
 
  803    NSDictionary            *newSM = 
nil;
 
  804    NSMutableDictionary     *cleanSM = 
nil;
 
  806    NSEnumerator            *stateEnum = 
nil;
 
  807    NSString                *stateKey = 
nil;
 
  808    NSDictionary            *stateHandlers = 
nil;
 
  809    NSAutoreleasePool       *pool = 
nil;
 
  811    if (![smName isEqualToString:
@"nullAI.plist"])
 
  815        if (newSM != 
nil && ![newSM isKindOfClass:[NSDictionary 
class]])  
return nil; 
 
  821        OOLog(
@"ai.load", 
@"Loading and sanitizing AI \"%@\
"", smName);
 
  836                NSString *fromString = 
@"";
 
  837                if ([
self state] != 
nil)
 
  839                    fromString = [
NSString stringWithFormat:@" from %@:%@", [
self name], [
self state]];
 
  841                OOLog(
@"ai.load.failed.unknownAI", 
@"Can't switch AI for %@%@ to \"%@\
" - could not load file.", [[
self owner] shortDescription], fromString, smName);
 
  847            for (stateEnum = [newSM keyEnumerator]; (stateKey = [
stateEnum nextObject]); )
 
  849                stateHandlers = [
newSM objectForKey:stateKey];
 
  850                if (![stateHandlers isKindOfClass:[NSDictionary 
class]])
 
  852                    OOLogWARN(
@"ai.invalidFormat.state", 
@"State \"%@\
" in AI \"%@\" is not a dictionary, ignoring.", stateKey, smName);
 
  857                [
cleanSM setObject:stateHandlers forKey:stateKey];
 
  859            [
cleanSM setObject:script forKey:@"jsScript"];
 
  862            newSM = [[
cleanSM copy] autorelease];
 
  865            if ([[NSUserDefaults standardUserDefaults] boolForKey:
@"generate-ai-graphviz"])
 
  867                GenerateGraphVizForAIStateMachine(newSM, smName);
 
   801- (NSDictionary *) loadStateMachine:(NSString *)smName jsName:(NSString *)script {
…}
  
  888- (NSDictionary *) cleanHandlers:(NSDictionary *)handlers forState:(NSString *)stateKey stateMachine:(NSString *)smName
 
  890    NSEnumerator            *handlerEnum = 
nil;
 
  891    NSString                *handlerKey = 
nil;
 
  892    NSArray                 *handlerActions = 
nil;
 
  893    NSMutableDictionary     *result = 
nil;
 
  896    for (handlerEnum = [handlers keyEnumerator]; (handlerKey = [
handlerEnum nextObject]); )
 
  898        handlerActions = [
handlers objectForKey:handlerKey];
 
  899        if (![handlerActions isKindOfClass:[NSArray 
class]])
 
  901            OOLogWARN(
@"ai.invalidFormat.handler", 
@"Handler \"%@\
" for state \"%@\" in AI \"%@\" is not an array, ignoring.", handlerKey, stateKey, smName);
 
  906        [
result setObject:handlerActions forKey:handlerKey];
 
  910    return [[
result copy] autorelease];
 
   888- (NSDictionary *) cleanHandlers:(NSDictionary *)handlers forState:(NSString *)stateKey stateMachine:(NSString *)smName {
…}
  
  914- (NSArray *) cleanActions:(NSArray *)actions forHandler:(NSString *)handlerKey state:(NSString *)stateKey stateMachine:(NSString *)smName
 
  916    NSEnumerator            *actionEnum = 
nil;
 
  917    NSString                *action = 
nil;
 
  919    NSString                *selector = 
nil;
 
  920    id                      aliasedSelector = 
nil;
 
  921    NSMutableArray          *result = 
nil;
 
  922    static NSSet            *whitelist = 
nil;
 
  923    static NSDictionary     *aliases = 
nil;
 
  924    NSArray                 *whitelistArray1 = 
nil;
 
  925    NSArray                 *whitelistArray2 = 
nil;
 
  927    if (whitelist == 
nil)
 
  930        if (whitelistArray1 == 
nil)  whitelistArray1 = [
NSArray array];
 
  932        if (whitelistArray2 != 
nil)  whitelistArray1 = [
whitelistArray1 arrayByAddingObjectsFromArray:whitelistArray2];
 
  934        whitelist = [[
NSSet alloc] initWithArray:whitelistArray1];
 
  939    for (actionEnum = [actions objectEnumerator]; (action = [
actionEnum nextObject]); )
 
  941        if (![action isKindOfClass:[NSString 
class]])
 
  943            OOLogWARN(
@"ai.invalidFormat.action", 
@"An action in handler \"%@\
" for state \"%@\" in AI \"%@\" is not a string, ignoring.", handlerKey, stateKey, smName);
 
  951        spaceRange = [
action rangeOfString:@" "];
 
  952        if (spaceRange.location == NSNotFound)  selector = action;
 
  953        else  selector = [
action substringToIndex:spaceRange.location];
 
  956        aliasedSelector = [
aliases objectForKey:selector];
 
  957        if (aliasedSelector != 
nil)
 
  959            if ([aliasedSelector isKindOfClass:[NSString 
class]])
 
  962                selector = aliasedSelector;
 
  963                if (spaceRange.location == NSNotFound)  action = aliasedSelector;
 
  964                else action = [
aliasedSelector stringByAppendingString:[
action substringFromIndex:spaceRange.location]];
 
  966            else if ([aliasedSelector isKindOfClass:[NSArray 
class]] && [aliasedSelector 
count] != 0)
 
  975        if (![whitelist containsObject:selector])
 
  977            OOLog(
@"ai.unpermittedMethod", 
@"Handler \"%@\
" for state \"%@\" in AI \"%@\" uses \"%@\", which is not a permitted AI method.", handlerKey, stateKey, smName, selector);
 
  981        [
result addObject:action];
 
  985    return [[
result copy] autorelease];
 
   914- (NSArray *) cleanActions:(NSArray *)actions forHandler:(NSString *)handlerKey state:(NSString *)stateKey stateMachine:(NSString *)smName {
…}
  
  993- (id) initWithStateMachine:(NSDictionary *)stateMachine
 
  994                       name:(NSString *)name
 
  995                      state:(NSString *)state
 
  996            pendingMessages:(NSSet *)pendingMessages
 
  997                                     jsScript:(NSString *)script
 
  999    if ((
self = [super init]))
 
 1002        _name = [name copy];
 
   993- (id) initWithStateMachine:(NSDictionary *)stateMachine {
…}
  
 1014    [_stateMachine autorelease];
 
 1015    [_name autorelease];
 
 1016    [_state autorelease];
 
 1017    [_pendingMessages autorelease];
 
 1018    [_jsScript autorelease];
 
 
#define AI_THINK_INTERVAL
 
static AI * sCurrentlyRunningAI
 
static AIStackElement * sStack
 
void OOLogPushIndent(void)
 
#define OOLogWARN(class, format,...)
 
#define OOLogERR(class, format,...)
 
NSString *const kOOLogException
 
void OOLogPopIndent(void)
 
BOOL OOLogWillDisplayMessagesInClass(NSString *inMessageClass)
 
#define OOLog(class, format,...)
 
#define OOLogIndentIf(class)
 
NSDictionary * OODictionaryFromFile(NSString *path)
 
NSMutableArray * ScanTokensFromString(NSString *values)
 
void setStateMachine:withJSScript:(NSString *smName,[withJSScript] NSString *script)
 
NSDictionary * stateMachine
 
NSString * descriptionComponents()
 
NSArray * cleanActions:forHandler:state:stateMachine:(NSArray *actions,[forHandler] NSString *handlerKey,[state] NSString *stateKey,[stateMachine] NSString *smName)
 
NSString * currentlyRunningAIDescription()
 
void reportStackOverflow()
 
void directSetState:(NSString *state)
 
NSMutableSet * pendingMessages
 
NSDictionary * loadStateMachine:jsName:(NSString *smName,[jsName] NSString *script)
 
void directSetStateMachine:name:(NSDictionary *newSM,[name] NSString *name)
 
void debugDumpPendingMessages()
 
void preserveCurrentStateMachine()
 
AI * currentlyRunningAI()
 
void restorePreviousStateMachine()
 
NSString * shortDescriptionComponents()
 
OOTimeDelta thinkTimeInterval
 
NSDictionary * cleanHandlers:forState:stateMachine:(NSDictionary *handlers,[forState] NSString *stateKey,[stateMachine] NSString *smName)
 
void takeAction:(NSString *action)
 
BOOL hasSuspendedStateMachines()
 
OOTimeAbsolute nextThinkTime
 
NSString * stateMachineName
 
NSString * associatedJS()
 
void performDeferredCall:withObject:afterDelay:(SEL selector,[withObject] id object,[afterDelay] NSTimeInterval delay)
 
void reactToMessage:context:(NSString *message,[context] NSString *debugContext)
 
OOUniversalID universalID
 
void setObject:forKey:inCache:(id inElement,[forKey] NSString *inKey,[inCache] NSString *inCacheKey)
 
id objectForKey:inCache:(NSString *inKey,[inCache] NSString *inCacheKey)
 
OOCacheManager * sharedCache()
 
NSSet * pendingMessages()
 
NSDictionary * stateMachine()
 
NSMutableSet * _pendingMessages
 
NSDictionary * _stateMachine
 
NSString * pathForFileNamed:inFolder:(NSString *fileName,[inFolder] NSString *folderName)
 
NSDictionary * whitelistDictionary()
 
unsigned reportAIMessages
 
void setAIScript:(NSString *aiString)