Triggerable = { CLASS = "Triggerable" }
Triggerable.__index = Triggerable
function Triggerable:new()
local tr = { }
setmetatable(tr, self)
self.__index = self
tr.triggerers = { }
tr.dgn_trigs_by_type = { }
return tr
end
function Triggerable:add_triggerer(triggerer)
if not triggerer.type then
error("triggerer has no type")
end
table.insert(self.triggerers, triggerer)
if (triggerer.method == "dgn_event") then
local et = dgn.dgn_event_type(triggerer.type)
if not self.dgn_trigs_by_type[et] then
self.dgn_trigs_by_type[et] = {}
end
table.insert(self.dgn_trigs_by_type[et], #self.triggerers)
else
local method = triggerer.method or "(nil)"
local class
local meta = getmetatable(triggerer)
if not meta then
class = "(no meta table)"
elseif not meta.CLASS then
class = "(no class name)"
end
error("Unknown triggerer method '" .. method .. "' for trigger class '"
.. class .. "'")
end
triggerer:added(self)
end
function Triggerable:move(marker, dest, y)
local was_activated = self.activated
self:remove_all_triggerers(marker)
if y then
marker:move(dest, y)
else
marker:move(dest)
end
if was_activated then
self.activated = false
self:activate(marker)
end
end
function Triggerable:remove(marker)
if self.removed then
error("Trigerrable already removed")
end
self:remove_all_triggerers(marker)
dgn.remove_marker(marker)
self.removed = true
end
function Triggerable:remove_all_triggerers(marker)
for _, trig in ipairs(self.triggerers) do
trig:remove(self, marker)
end
end
function Triggerable:activate(marker)
if self.removed then
error("Can't activate, trigerrable removed")
end
if self.activating then
error("Triggerable already activating")
end
if self.activated then
error("Triggerable already activated")
end
self.activating = true
for _, trig in ipairs(self.triggerers) do
trig:activate(self, marker)
end
self.activating = false
self.activated = true
end
function Triggerable:event(marker, ev)
local et = ev:type()
local trig_list = self.dgn_trigs_by_type[et]
if not trig_list then
local class = getmetatable(self).CLASS
local x, y = marker:pos()
local e_type = dgn.dgn_event_type(et)
error("Triggerable type " .. class .. " at (" ..x .. ", " .. y .. ") " ..
"has no triggerers for dgn_event " .. e_type )
end
for _, trig_idx in ipairs(trig_list) do
self.triggerers[trig_idx]:event(self, marker, ev)
if self.removed then
return
end
end
end
function Triggerable:write(marker, th)
file.marshall(th, #self.triggerers)
for _, trig in ipairs(self.triggerers) do
file.marshall(th, getmetatable(trig).CLASS)
trig:write(marker, th)
end
lmark.marshall_table(th, self.dgn_trigs_by_type)
end
function Triggerable:read(marker, th)
self.triggerers = {}
local num_trigs = file.unmarshall_number(th)
for i = 1, num_trigs do
local trig_class = file.unmarshall_string(th)
local trig_table = _G[trig_class].read(nil, marker, th)
table.insert(self.triggerers, trig_table)
end
self.dgn_trigs_by_type = lmark.unmarshall_table(th)
setmetatable(self, Triggerable)
return self
end
DgnTriggerer = { CLASS = "DgnTriggerer" }
DgnTriggerer.__index = DgnTriggerer
function DgnTriggerer:new(pars)
pars = pars or {}
if not pars.type then
error("DgnTriggerer must have a type")
end
if pars.type == "monster_dies" or pars.type == "item_moved"
or pars.type == "item_pickup"
then
if not pars.target then
error(pars.type .. " DgnTriggerer must have parameter 'target'")
end
end
local tr = util.copy_table(pars)
setmetatable(tr, self)
self.__index = self
tr:setup()
return tr
end
function DgnTriggerer:setup()
self.method = "dgn_event"
end
function DgnTriggerer:added(triggerable)
if self.type == "item_pickup" then
local mover = util.copy_table(self)
mover.type = "item_moved"
mover.marker_mover = true
triggerable:add_triggerer( DgnTriggerer:new(mover) )
end
end
function DgnTriggerer:activate(triggerable, marker)
if not (triggerable.activated or triggerable.activating) then
error("DgnTriggerer:activate(): triggerable is not activated")
end
local et = dgn.dgn_event_type(self.type)
if (dgn.dgn_event_is_position(et)) then
dgn.register_listener(et, marker, marker:pos())
else
dgn.register_listener(et, marker)
end
end
function DgnTriggerer:remove(triggerable, marker)
if not triggerable.activated then
return
end
local et = dgn.dgn_event_type(self.type)
if (dgn.dgn_event_is_position(et)) then
dgn.remove_listener(marker, marker:pos())
else
dgn.remove_listener(marker)
end
end
function DgnTriggerer:event(triggerable, marker, ev)
if self.type == "monster_dies" then
local midx = ev:arg1()
local mons = dgn.mons_from_index(midx)
if not mons then
error("DgnTriggerer:event() didn't get a valid monster index")
end
if mons.name == self.target then
triggerable:on_trigger(self, marker, ev)
end
elseif self.type == "feat_change" then
if self.target and self.target ~= "" then
local feat = dgn.feature_name(dgn.grid(ev:pos()))
if not string.find(feat, self.target) then
return
end
end
triggerable:on_trigger(self, marker, ev)
elseif self.type == "item_moved" then
local obj_idx = ev:arg1()
local it = dgn.item_from_index(obj_idx)
if not it then
error("DgnTriggerer:event() didn't get a valid item index")
end
if item.name(it) == self.target then
if self.marker_mover then
triggerable:move(marker, ev:dest())
else
triggerable:on_trigger(self, marker, ev)
end
end
elseif self.type == "item_pickup" then
local obj_idx = ev:arg1()
local it = dgn.item_from_index(obj_idx)
if not it then
error("DgnTriggerer:event() didn't get a valid item index")
end
if item.name(it) == self.target then
triggerable:on_trigger(self, marker, ev)
end
else
local e_type = dgn.dgn_event_type(et)
error("DgnTriggerer can't handle events of type " .. e_type)
end
end
function DgnTriggerer:write(marker, th)
self.method = nil
lmark.marshall_table(th, self)
end
function DgnTriggerer:read(marker, th)
local tr = lmark.unmarshall_table(th)
setmetatable(tr, DgnTriggerer)
tr:setup()
return tr
end