Jump to content

Reading Lua: DST


Recommended Posts

Hi guys,

In the early stages of teaching myself to mod and reading through DST code. I've seen the great guides around the forums and just wanted to test my understanding of what the Lua text I am reading means. For an example I am looking at houndbrain.lua

 

Spoiler

require "behaviours/wander"
require "behaviours/chaseandattack"
require "behaviours/panic"
require "behaviours/attackwall"
require "behaviours/minperiod"
require "behaviours/leash"
require "behaviours/faceentity"
require "behaviours/doaction"
require "behaviours/standstill"

local HoundBrain = Class(Brain, function(self, inst)
    Brain._ctor(self, inst)
    --self.reanimatetime = nil
end)

local SEE_DIST = 30

local MIN_FOLLOW_LEADER = 2
local MAX_FOLLOW_LEADER = 6
local TARGET_FOLLOW_LEADER = (MAX_FOLLOW_LEADER + MIN_FOLLOW_LEADER) / 2

local LEASH_RETURN_DIST = 10
local LEASH_MAX_DIST = 40

local HOUSE_MAX_DIST = 40
local HOUSE_RETURN_DIST = 50

local SIT_BOY_DIST = 10

local function EatFoodAction(inst)
    local target = FindEntity(inst, SEE_DIST, function(item) return inst.components.eater:CanEat(item) and item:IsOnPassablePoint(true) end)
    return target ~= nil and BufferedAction(inst, target, ACTIONS.EAT) or nil
end

local function GetLeader(inst)
    return inst.components.follower ~= nil and inst.components.follower.leader or nil
end

local function GetHome(inst)
    return inst.components.homeseeker ~= nil and inst.components.homeseeker.home or nil
end

local function GetHomePos(inst)
    local home = GetHome(inst)
    return home ~= nil and home:GetPosition() or nil
end

local function GetNoLeaderLeashPos(inst)
    return GetLeader(inst) == nil and GetHomePos(inst) or nil
end

local function GetWanderPoint(inst)
    local target = GetLeader(inst) or inst:GetNearestPlayer(true)
    return target ~= nil and target:GetPosition() or nil
end

local function ShouldStandStill(inst)
    return inst:HasTag("pet_hound") and not TheWorld.state.isday and not GetLeader(inst) and not inst.components.combat:HasTarget() and inst:IsNear(GetHome(inst), SIT_BOY_DIST)
end

local function TryReanimate(self)
    local leader = GetLeader(self.inst)
    if leader ~= nil then
        if leader.sg ~= nil and leader.sg:HasStateTag("statue") then
            self.reanimatetime = nil
        elseif self.reanimatetime == nil then
            self.reanimatetime = GetTime() + math.random() * .5
        elseif self.reanimatetime == true then
            self.inst:PushEvent("reanimate", { target = leader.components.combat.target })
        elseif self.reanimatetime < GetTime() then
            self.reanimatetime = true
        end
    else
        local player, dsq = self.inst:GetNearestPlayer(true)
        if player == nil or dsq >= 25 then
            self.reanimatetime = nil
        elseif self.reanimatetime == nil then
            self.reanimatetime = GetTime() + 3
        elseif self.reanimatetime == true then
            self.inst:PushEvent("reanimate", { target = player })
        elseif self.reanimatetime < GetTime() then
            self.reanimatetime = true
        end
    end
end

local function ShouldBecomeStatue(inst)
    local leader = GetLeader(inst)
    return leader ~= nil and leader.sg ~= nil and leader.sg:HasStateTag("statue") and inst:IsNear(leader, 10)
end

local function GetClayLeaderLeashPos(inst)
    local leader = GetLeader(inst)
    if leader == nil or inst.leader_offset == nil then
        return
    end
    local x, y, z = leader.Transform:GetWorldPosition()
    return Vector3(x + inst.leader_offset.x, 0, z + inst.leader_offset.z)
end

local function FaceFormation(inst)
    if inst.sg:HasStateTag("canrotate") then
        local leader = GetLeader(inst)
        if leader ~= nil then
            inst.Transform:SetRotation(leader.Transform:GetRotation())
        end
    end
end

function HoundBrain:OnStart()
    local root = PriorityNode(
        self.inst:HasTag("clay") and
        --clay hound brain
        {
            WhileNode(function() return self.inst.sg:HasStateTag("statue") end, "Statue",
                ActionNode(function() TryReanimate(self) end, "TryReanimate")),

            WhileNode(function() return GetLeader(self.inst) == nil end, "NoLeader", AttackWall(self.inst)),

            ChaseAndAttack(self.inst, 10),

            WhileNode(function() return ShouldBecomeStatue(self.inst) end, "BecomeStatue",
                ParallelNode{
                    LoopNode{
                        WaitNode(3),
                        ActionNode(function() self.inst:PushEvent("becomestatue") end),
                    },
                    PriorityNode({
                        Leash(self.inst, GetClayLeaderLeashPos, 1, 1),
                        FailIfSuccessDecorator(ActionNode(function() FaceFormation(self.inst) end, "FaceFormation")),
                        StandStill(self.inst),
                    }, .25),
                }),

            Leash(self.inst, GetClayLeaderLeashPos, 1, 1),

            Follow(self.inst, GetLeader, MIN_FOLLOW_LEADER, TARGET_FOLLOW_LEADER, MAX_FOLLOW_LEADER),
            FaceEntity(self.inst, GetLeader, GetLeader),

            WhileNode(function() return GetLeader(self.inst) == nil end, "Abandoned",
                ParallelNode{
                    LoopNode{
                        WaitNode(3),
                        ActionNode(function() self.inst:PushEvent("becomestatue") end),
                    },
                    PriorityNode({
                        WhileNode(function() return GetHome(self.inst) end, "HasHome", Wander(self.inst, GetHomePos, 8)),
                        Wander(self.inst, GetWanderPoint, 20),
                    }, .25),
                }),

            WhileNode(function() return GetHome(self.inst) end, "HasHome", Wander(self.inst, GetHomePos, 8)),
            Wander(self.inst, GetWanderPoint, 20),
        } or
        --regular hound brains
        {
            WhileNode(function() return not self.inst.sg:HasStateTag("jumping") end, "NotJumpingBehaviour",
                PriorityNode({
                    WhileNode(function() return self.inst.components.hauntable and self.inst.components.hauntable.panic end, "PanicHaunted", Panic(self.inst)),
                    WhileNode(function() return self.inst.components.health.takingfiredamage end, "OnFire", Panic(self.inst)),
                    WhileNode(function() return GetLeader(self.inst) == nil end, "NoLeader", AttackWall(self.inst)),

                    WhileNode(function() return self.inst:HasTag("pet_hound") end, "Is Pet", ChaseAndAttack(self.inst, 10)),
                    WhileNode(function() return not self.inst:HasTag("pet_hound") and GetHome(self.inst) ~= nil end, "No Pet Has Home", ChaseAndAttack(self.inst, 10, 20)),
                    WhileNode(function() return not self.inst:HasTag("pet_hound") and GetHome(self.inst) == nil end, "Not Pet", ChaseAndAttack(self.inst, 100)),

                    Leash(self.inst, GetNoLeaderLeashPos, HOUSE_MAX_DIST, HOUSE_RETURN_DIST),

                    DoAction(self.inst, EatFoodAction, "eat food", true),
                    Follow(self.inst, GetLeader, MIN_FOLLOW_LEADER, TARGET_FOLLOW_LEADER, MAX_FOLLOW_LEADER),
                    FaceEntity(self.inst, GetLeader, GetLeader),

                    StandStill(self.inst, ShouldStandStill),

                    WhileNode(function() return GetHome(self.inst) end, "HasHome", Wander(self.inst, GetHomePos, 8)),
                    Wander(self.inst, GetWanderPoint, 20),
                }, .25)
            ),
        }, .25 )

    self.bt = BT(self.inst, root)
end

return HoundBrain

My issue currently is understaning basic language and what it means, EG local target vs return target.

For example:

local function EatFoodAction(inst) <<this is the action that the following lines define, in this case whether the hound targets and eats food.>>
    local target <<if the following information returns true then the item will be targetted?>> = FindEntity(inst <<probably needlessly obsessing, but I can't for the life of me figure out what the use of "inst" is and its effect despite it being everywhere in the code>> , SEE_DIST <<check the distance the item is from the hound>>, function(item) return inst.components.eater:CanEat(item) <<item returns the value that it can be eaten>> and item:IsOnPassablePoint(true) <<item is ALSO on a point the hound can walk on>> end_ <<surprisingly difficult to find what the Lua keywords actually do, but end seems to complete this 'string?' in order to prevent unneeded repetition?>>
    return target ~= nil <<if the above is true, then change current target to no target>> and BufferedAction(inst, target, ACTIONS.EAT) <<and perfrom the action of eating>> or nil <<not sure what the "or nil" does here, is it there in case the target food item has disappeared in the interim so the hound will return to the start of its brain behaviour?>>

I am also assuming that the priority of the hounds behaviour follows the order of the local function in the script (top to bottom). E.G. it will first and foremost prioritize eating food, then getting a leader, then getting a home, wandering, standing still, reanimating, etc. as the values return true or false? By my reading therefore behaviorally, in game, the hound will prioritize food over all else, then following its leader (e.g. Varg), attacking any player within 25 distance, if no leader attacking walls, and then wandering.

So I can take from this that hounds summoned by the Varg will not attack walls, whereas normal hounds will because:
   WhileNode(function() return GetLeader(self.inst) == nil end, "NoLeader", AttackWall(self.inst)) <<Varg's hounds will succesfully 'get' a leader, thereby not triggering the "AttackWall" command>>

Feedback greatly appreciated!

 

 

Edited by Laisanalgaib
Link to comment
Share on other sites

I'm sorry to say, but almost none of what you wrote is accurate. Have you done the Lua Crash Course? It's linked in this newcomer post, which also introduces a bunch of tips for you to get started. After that, you should no longer be this confused :) You got the priority-part kind of right. It's a state-machine, so it has a hierarchy of states to check for. Each state is prioritized, but also has a function to check whether the state is valid at this moment, so you can e.g. make a hound skip looking for food if it doesn't have a leader yet, and things like that.

Edited by Ultroman
  • Like 1
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
  • Create New...