These are all linux offsets by the way (should be in gamedata really but it's all hardcoded here).
Small methodmap for the Actions:
PHP Code:
#define OFFSET_BEHAVIOR 8
#define OFFSET_PARENT 12
#define OFFSET_CHILD 16
#define OFFSET_BURIED 20
#define OFFSET_COVERING 24
methodmap BehaviorAction
{
public BehaviorAction(Address action)
{
return view_as<BehaviorAction>(action);
}
public void GetName(char[] returnString, int maxlength)
{
static Handle sdkHandle;
if (sdkHandle == INVALID_HANDLE)
{
StartPrepSDKCall(SDKCall_Raw);
PrepSDKCall_SetVirtual(41);
PrepSDKCall_SetReturnInfo(SDKType_String, SDKPass_Pointer);
sdkHandle = EndPrepSDKCall();
}
SDKCall(sdkHandle, this, returnString, maxlength);
}
property Address address
{
public get()
{
return view_as<Address>(this);
}
}
property bool isNull
{
public get()
{
return view_as<Address>(this) == Address_Null;
}
}
property Address m_behavior // the Behavior this Action is part of
{
public get()
{
return view_as<Address>(LoadFromAddress(view_as<Address>(this) + view_as<Address>(OFFSET_BEHAVIOR), NumberType_Int32));
}
}
property BehaviorAction m_parent // the Action that contains us
{
public get()
{
return view_as<BehaviorAction>(LoadFromAddress(view_as<Address>(this) + view_as<Address>(OFFSET_PARENT), NumberType_Int32));
}
}
property BehaviorAction m_child // the ACTIVE Action we contain, top of the stack. Use m_buriedUnderMe, m_coveringMe on the child to traverse to other suspended children
{
public get()
{
return view_as<BehaviorAction>(LoadFromAddress(view_as<Address>(this) + view_as<Address>(OFFSET_CHILD), NumberType_Int32));
}
}
property BehaviorAction m_buriedUnderMe // the Action just "under" us in the stack that we will resume to when we finish
{
public get()
{
return view_as<BehaviorAction>(LoadFromAddress(view_as<Address>(this) + view_as<Address>(OFFSET_BURIED), NumberType_Int32));
}
}
property BehaviorAction m_coveringMe // the Action just "above" us in the stack that will resume to us when it finishes
{
public get()
{
return view_as<BehaviorAction>(LoadFromAddress(view_as<Address>(this) + view_as<Address>(OFFSET_COVERING), NumberType_Int32));
}
}
}
And a small use example, GetTopLevelAction will return the name of the current Action, entity can be any NextBot derivative (common infected, witch, survivor bot, special infected).
PHP Code:
void GetTopLevelAction(char[] returnString, int maxlength, int entity)
{
Address nextBot = MyNextBotPointer(entity);
Address intention = GetIntentionInterface(nextBot);
Address behavior = FirstContainedResponder(intention);
Address startingAction = FirstContainedResponder(behavior);
BehaviorAction action = BehaviorAction(startingAction);
while (action.m_child.isNull == false)
{
action = action.m_child;
}
action.GetName(returnString, maxlength);
}
Address MyNextBotPointer(int entity)
{
static Handle sdkHandle = INVALID_HANDLE;
if (sdkHandle == INVALID_HANDLE)
{
StartPrepSDKCall(SDKCall_Entity);
PrepSDKCall_SetVirtual(82);
PrepSDKCall_SetReturnInfo(SDKType_PlainOldData, SDKPass_Plain);
sdkHandle = EndPrepSDKCall();
}
return view_as<Address>(SDKCall(sdkHandle, entity));
}
Address GetIntentionInterface(Address nextBotPointer)
{
static Handle sdkHandle = INVALID_HANDLE;
if (sdkHandle == INVALID_HANDLE)
{
StartPrepSDKCall(SDKCall_Raw);
PrepSDKCall_SetVirtual(50);
PrepSDKCall_SetReturnInfo(SDKType_PlainOldData, SDKPass_Plain);
sdkHandle = EndPrepSDKCall();
}
return view_as<Address>(SDKCall(sdkHandle, nextBotPointer));
}
Address FirstContainedResponder(Address address)
{
static Handle sdkHandle = INVALID_HANDLE;
if (sdkHandle == INVALID_HANDLE)
{
StartPrepSDKCall(SDKCall_Raw);
PrepSDKCall_SetVirtual(2);
PrepSDKCall_SetReturnInfo(SDKType_PlainOldData, SDKPass_Plain);
sdkHandle = EndPrepSDKCall();
}
return view_as<Address>(SDKCall(sdkHandle, intentionInterface));
}