It depends on project setup and how you prefer your workflow.
If you have a lot of programmers then I would go with LUA module. Inheritance through meta-tables could be an option if you wish to lock down and prevent read/write to tables, but personally I think they only add overhead compared to the trust factor of a good code convention.
If you have Designers who like tweaking values and behaviours, then I would setup scripts that hook in to a shared table for the game-object. This allow you to create very modular systems, but the lack of editor tooling makes it a bit heavy to shift through. I made a similar thing in DefKit, but that relies on message-passing and could be less performant in large scale.
Since your implementation will be a bit more focused on states here, each script could be a separate state injected to a state-machine driven through another script.
State Flee
local state_machine = require "core.state_machine"
local function on_message(self, message_id, ...)
state_machine.enter(hash("attack")
end
function init(self)
state_machine.add(hash("flee"), {
--on_enter = enter,
--on_exit = exit,
on_message = on_message,
--on_update,
}
end
State Machine
local M = {}
local obj_states = {}
function M.add(name, state)
local gid = go.get_id()
local states = obj_states[gid] or {}
states[name] = state
obj_states[gid] = states
end
...
return M