Behave/behave.moon
2018-03-16 00:07:40 -07:00

101 lines
2.1 KiB
Plaintext

local make, Node, Decorate
running = setmetatable {}, __tostring: -> return "running"
get_nodes = (tab) ->
nodes = {}
for node in *tab
table.insert nodes, make node
return nodes
-- produces a callable function from a defined node or full behavior tree
make = (tab) ->
if "function" == type tab
return tab
elseif "function" == type tab.type
return tab.type tab
elseif tab.decorate
return Decorate tab
else
return Node tab
-- complex leaf node
-- state is preserved through calls, optional start/finish functions
Node = (tab) ->
state, started = {}, false
return (...) ->
local result
unless started
result = tab.start state, ... if tab.start
started = true unless result == false
result = tab.run state, ... unless result == false
if result != running
started = false
result = tab.finish state, ... if result and tab.finish
return result
-- modifies the result of a node before returning it
Decorator = (tab) ->
node = make tab[1]
return (...) ->
result = node object, ...
result = tab.decorate result, ... unless result == running
return result
-- returns first success/running, or failure
Selector = (tab) ->
nodes = get_nodes tab
length = #nodes
i = 1
return (...) ->
result = nodes[i](...)
while not result
i += 1
if i > length
i = 1
return false
result = nodes[i](...)
i = 1 if result != running
return result
-- returns first running/failure, or success
Sequence = (tab) ->
nodes = get_nodes tab
length = #nodes
i = 1
return (...) ->
result = nodes[i](...)
while result and result != running
i += 1
if i > length
i = 1
return result
result = nodes[i](...)
i = 1 unless result
return result
-- returns success/running/failure from random child
Random = (tab) ->
nodes = get_nodes tab
length = #nodes
local r
return (...) ->
unless r
r = 1 + math.random length
result = nodes[r](...)
unless result == running
r = nil
return result
{
success: true
:running
failure: false
:Node
:Decorator
:Selector
:Sequence
:Random
}