diff --git a/init.lua b/init.lua index acfa3ba..a249bb9 100644 --- a/init.lua +++ b/init.lua @@ -3,23 +3,25 @@ local Nodes = {} local function NodeStart(node, args) -- don't start again if started - if node.data then return end + if node._started then return end - node.data = node.parent and node.parent.data or args + node.data = node.parent and node.parent.data or args or node.data node.data[node] = node.data[node] or {} node:_start() + + node._started = true end -local function NodeUpdate(node) - -- don't tick if not started - if not node.data then return end +local function NodeUpdate(node, ...) + -- automatically start if not started + if not node._started then NodeStart(node) end - local result = node:_tick() + local result = node:_tick(...) if type(result) == 'boolean' then node:_finish() - node.data = nil + node._started = false end return result @@ -72,8 +74,10 @@ function Tactree.Composite(name) end end -function Tactree.Tree(name) - if not Nodes[name] then error('no such node \'' .. name .. '\'', 2) end +local function tree_by_name(name, depth) + depth = depth or 2 + + if not Nodes[name] then error('no such node \'' .. name .. '\'', depth) end local node = {} node.children = {} @@ -85,7 +89,7 @@ function Tactree.Tree(name) -- find a way to prevent this? if Nodes[name].children then for _, child in ipairs(Nodes[name].children) do - local cn = Tactree.Tree(child) + local cn = tree_by_name(child, depth + 1) cn.parent = node table.insert(node.children, cn) end @@ -94,27 +98,59 @@ function Tactree.Tree(name) return setmetatable(node, { __index = Nodes[name], __tostring = function() return name end }) end +function Tactree.Tree(name) + if not Nodes[name] then error('no such node \'' .. name .. '\'', 2) end + + return function(children) + local node = {} + node.children = {} + node.start = NodeStart + node.update = NodeUpdate + node.private = NodePrivateData + + -- add pre-defined children + if Nodes[name].children then + for _, child in ipairs(Nodes[name].children) do + local cn = tree_by_name(child, 3) + cn.parent = node + table.insert(node.children, cn) + end + end + + -- add extra children from call + for _, child in ipairs(children) do + local cn + if type(child) == 'string' then + cn = tree_by_name(child, 3) + elseif type(child) == 'table' then + cn = child + else + error('invalid child type: \'' .. type(child) '\'', 3) + end + + cn.parent = node + table.insert(node.children, cn) + end + + return setmetatable(node, { __index = Nodes[name], __tostring = function() return name end }) + end +end + Tactree.Leaf 'Sequence' { start = function(node) node:private().current_child = 1 - node.children[node:private().current_child]:start() end, - tick = function(node) - local result = node.children[node:private().current_child]:update() - - if type(result) == 'boolean' then + tick = function(node, ...) + local result + repeat + result = node.children[node:private().current_child]:update(...) if result then - if node:private().current_child == #node.children then - return true - else - node:private().current_child = node:private().current_child + 1 - node.children[node:private().current_child]:start() - end - else - return false + node:private().current_child = node:private().current_child + 1 end - end + until (not result) or (node:private().current_child > #node.children) + + return result end } @@ -122,23 +158,17 @@ Tactree.Leaf 'Selector' { start = function(node) node:private().current_child = 1 - node.children[node:private().current_child]:start() end, - tick = function(node) - local result = node.children[node:private().current_child]:update() - - if type(result) == 'boolean' then - if not result then - if node:private().current_child == #node.children then - return false - else - node:private().current_child = node:private().current_child + 1 - node.children[node:private().current_child]:start() - end - else - return true + tick = function(node, ...) + local result + repeat + result = node.children[node:private().current_child]:update(...) + if result then + node:private().current_child = node:private().current_child + 1 end - end + until (result ~= false) or (node:private().current_child > #node.children) + + return result end } @@ -147,61 +177,13 @@ Tactree.Leaf 'Inverter' start = function(node) node.children[1]:start() end, - tick = function(node) - local result = node.children[1]:update() + tick = function(node, ...) + local result = node.children[1]:update(...) if type(result) == 'boolean' then return not result end end } -Tactree.Leaf 'RepeatUntilFail' -{ - start = function(node) - node.children[1]:start() - end, - tick = function(node) - local result = node.children[1]:update() - - if type(result) == 'boolean' then - if not result then - return true - else - node.children[1]:start() - end - end - end -} - -Tactree.Leaf 'RepeatUntilPass' -{ - start = function(node) - node.children[1]:start() - end, - tick = function(node) - local result = node.children[1]:update() - - if type(result) == 'boolean' then - if result then - return true - else - node.children[1]:start() - end - end - end -} - -Tactree.Leaf 'RepeatForever' -{ - start = function(node) - node.children[1]:start() - end, - tick = function(node) - local result = node.children[1]:update() - - if type(result) == 'boolean' then node.children[1]:start() end - end -} - --[[ Example usage -------------