View Single Post
Zynda
Member
Join Date: Jul 2011
Old 06-07-2021 , 05:49   Re: [L4D] Detect the bot intention
Reply With Quote #4

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[] returnStringint maxlength)
    {
        static 
Handle sdkHandle;

        if (
sdkHandle == INVALID_HANDLE)
        {
            
StartPrepSDKCall(SDKCall_Raw);
            
PrepSDKCall_SetVirtual(41);
            
PrepSDKCall_SetReturnInfo(SDKType_StringSDKPass_Pointer);
            
sdkHandle EndPrepSDKCall();
        }

        
SDKCall(sdkHandlethisreturnStringmaxlength);
    }

    
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[] returnStringint maxlengthint 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(returnStringmaxlength);
}

Address MyNextBotPointer(int entity)
{
    static 
Handle sdkHandle INVALID_HANDLE;
    if (
sdkHandle == INVALID_HANDLE)
    {
        
StartPrepSDKCall(SDKCall_Entity);
        
PrepSDKCall_SetVirtual(82);
        
PrepSDKCall_SetReturnInfo(SDKType_PlainOldDataSDKPass_Plain);

        
sdkHandle EndPrepSDKCall();
    }

    return 
view_as<Address>(SDKCall(sdkHandleentity));
}

Address GetIntentionInterface(Address nextBotPointer)
{
    static 
Handle sdkHandle INVALID_HANDLE;
    if (
sdkHandle == INVALID_HANDLE)
    {
        
StartPrepSDKCall(SDKCall_Raw);
        
PrepSDKCall_SetVirtual(50);
        
PrepSDKCall_SetReturnInfo(SDKType_PlainOldDataSDKPass_Plain);

        
sdkHandle EndPrepSDKCall();
    }

    return 
view_as<Address>(SDKCall(sdkHandlenextBotPointer));
}

Address FirstContainedResponder(Address address)
{
    static 
Handle sdkHandle INVALID_HANDLE;
    if (
sdkHandle == INVALID_HANDLE)
    {
        
StartPrepSDKCall(SDKCall_Raw);
        
PrepSDKCall_SetVirtual(2);
        
PrepSDKCall_SetReturnInfo(SDKType_PlainOldDataSDKPass_Plain);

        
sdkHandle EndPrepSDKCall();
    }

    return 
view_as<Address>(SDKCall(sdkHandleintentionInterface));

Zynda is offline