diff options
-rw-r--r-- | crawl-ref/source/dat/clua/lm_flags.lua | 267 | ||||
-rw-r--r-- | crawl-ref/source/dat/clua/lm_monst.lua | 135 | ||||
-rw-r--r-- | crawl-ref/source/dat/clua/lm_trig.lua | 352 | ||||
-rw-r--r-- | crawl-ref/source/dat/clua/luamark.lua | 2 | ||||
-rw-r--r-- | crawl-ref/source/dat/clua/util.lua | 20 | ||||
-rw-r--r-- | crawl-ref/source/dat/hells.des | 2 | ||||
-rw-r--r-- | crawl-ref/source/dgnevent.h | 10 | ||||
-rw-r--r-- | crawl-ref/source/l_dgnevt.cc | 26 |
8 files changed, 535 insertions, 279 deletions
diff --git a/crawl-ref/source/dat/clua/lm_flags.lua b/crawl-ref/source/dat/clua/lm_flags.lua index 4660fa5abb..3a2f3e1b5b 100644 --- a/crawl-ref/source/dat/clua/lm_flags.lua +++ b/crawl-ref/source/dat/clua/lm_flags.lua @@ -53,51 +53,43 @@ -- "item", which is the plain name of the item its watching -- (i.e., "Orb of Zot" and "golden rune of Zot" rather than -- "the Orb of Zot" or "a golden rune of Zot"). +-- +-- ChangeFlags is a Triggerable subclass, and the above three functions +-- are just convenience functions which add a single triggerer. Other +-- triggerers (or more than one) can be added. -------------------------------------------------------------------------- - -ChangeFlags = { CLASS = "ChangeFlags" } -ChangeFlags.__index = ChangeFlags -function ChangeFlags:_new() - local cf = { } - setmetatable(cf, self) - self.__index = self +require('clua/lm_trig.lua') - return cf -end +ChangeFlags = util.subclass(Triggerable) +ChangeFlags.CLASS = "ChangeFlags" function ChangeFlags:new(pars) pars = pars or { } + local cf = self.super.new(self) + pars.level_flags = pars.level_flags or "" pars.branch_flags = pars.branch_flags or "" pars.msg = pars.msg or "" - if pars.level_flags == "" and pars.branch_flags == "" - and not pars.trigger - then - error("Must provide at least one of level_flags, branch_flags, or trigger.") + if pars.level_flags == "" and pars.branch_flags == "" then + error("Must provide at least one of level_flags or branch_flags.") end - local cf = self:_new() cf.level_flags = pars.level_flags cf.branch_flags = pars.branch_flags cf.msg = pars.msg - cf.trigger = pars.trigger cf.props = { flag_group = pars.group } return cf end -function ChangeFlags:do_change(marker) +function ChangeFlags:on_trigger(triggerer, marker, ev) local did_change1 = false local did_change2 = false local silent = self.msg and self.msg ~= "" - if self.trigger then - self.trigger(marker) - end - if self.props.flag_group and self.props.flag_group ~= "" then local num_markers = dgn.num_matching_markers("flag_group", self.props.group) @@ -115,6 +107,8 @@ function ChangeFlags:do_change(marker) did_change2 = dgn.change_branch_flags(self.branch_flags, silent) end + self:remove(marker) + if did_change1 or did_change2 then if self.msg and self.msg ~= "" then crawl.mpr(self.smg) @@ -131,19 +125,22 @@ function ChangeFlags:property(marker, pname) end function ChangeFlags:write(marker, th) + ChangeFlags.super.write(self, marker, th) + file.marshall(th, self.level_flags) file.marshall(th, self.branch_flags) file.marshall(th, self.msg) - file.marshall_meta(th, self.trigger) lmark.marshall_table(th, self.props) end function ChangeFlags:read(marker, th) + ChangeFlags.super.read(self, marker, th) + self.level_flags = file.unmarshall_string(th) self.branch_flags = file.unmarshall_string(th) self.msg = file.unmarshall_string(th) - self.trigger = file.unmarshall_meta(th) self.props = lmark.unmarshall_table(th) + setmetatable(self, ChangeFlags) return self @@ -152,214 +149,56 @@ end -------------------------------------------------------------------------- -------------------------------------------------------------------------- -MonDiesChangeFlags = ChangeFlags:_new() -MonDiesChangeFlags.__index = MonDiesChangeFlags - -function MonDiesChangeFlags:_new(pars) - local mdcf - - if pars then - mdcf = ChangeFlags:new(pars) - else - mdcf = ChangeFlags:_new() - end - - setmetatable(mdcf, self) - self.__index = self - - return mdcf -end - -function MonDiesChangeFlags:new(pars) - pars = pars or { } - - if not pars.mon_name then - error("No monster name provided.") - end - - local mdcf = self:_new(pars) - mdcf.mon_name = pars.mon_name - - return mdcf -end - -function MonDiesChangeFlags:activate(marker) - dgn.register_listener(dgn.dgn_event_type('monster_dies'), marker) -end - -function MonDiesChangeFlags:event(marker, ev) - local midx = ev:arg1() - local mons = dgn.mons_from_index(midx) - - if not mons then - error("MonDiesChangeFlags:event() didn't get a valid monster index") - end - - if mons.name == self.mon_name then - ChangeFlags.do_change(self, marker) - dgn.remove_listener(marker) - dgn.remove_marker(marker) - end -end - -function MonDiesChangeFlags:write(marker, th) - ChangeFlags.write(self, marker, th) - file.marshall(th, self.mon_name) -end - -function MonDiesChangeFlags:read(marker, th) - ChangeFlags.read(self, marker, th) - self.mon_name = file.unmarshall_string(th) - setmetatable(self, MonDiesChangeFlags) - - return self -end - function mons_dies_change_flags(pars) - return MonDiesChangeFlags:new(pars) -end - ------------------------------------------------------------------------------ ------------------------------------------------------------------------------ -FeatChangeChangeFlags = ChangeFlags:_new() -FeatChangeChangeFlags.__index = FeatChangeChangeFlags - -function FeatChangeChangeFlags:_new(pars) - local fccf - - if pars then - fccf = ChangeFlags:new(pars) - else - fccf = ChangeFlags:_new() - end - - setmetatable(fccf, self) - self.__index = self - - return fccf -end - -function FeatChangeChangeFlags:new(pars) - pars = pars or { } - - local fccf = self:_new(pars) - - fccf.final_feat = pars.final_feat - - return fccf -end - -function FeatChangeChangeFlags:activate(marker) - dgn.register_listener(dgn.dgn_event_type('feat_change'), marker, - marker:pos()) -end - -function FeatChangeChangeFlags:event(marker, ev) - if self.final_feat and self.final_feat ~= "" then - local feat = dgn.feature_name(dgn.grid(ev:pos())) - if not string.find(feat, self.final_feat) then - return - end - end + local mon_name = pars.mon_name or pars.target - ChangeFlags.do_change(self, marker) - dgn.remove_listener(marker, marker:pos()) - dgn.remove_marker(marker) -end + pars.mon_name = nil + pars.target = nil -function FeatChangeChangeFlags:write(marker, th) - ChangeFlags.write(self, marker, th) - file.marshall(th, self.final_feat) -end + local cf = ChangeFlags:new(pars) -function FeatChangeChangeFlags:read(marker, th) - ChangeFlags.read(self, marker, th) - self.final_feat = file.unmarshall_string(th) - setmetatable(self, FeatChangeChangeFlags) + cf:add_triggerer( + DgnTriggerer:new { + type = "monster_dies", + target = mon_name + } + ) - return self + return cf end function feat_change_change_flags(pars) - return FeatChangeChangeFlags:new(pars) -end + local final_feat = pars.final_feat or pars.target --------------------------------------------------------------------------- --------------------------------------------------------------------------- + pars.final_feat = nil + pars.target = nil -ItemPickupChangeFlags = ChangeFlags:_new() -ItemPickupChangeFlags.__index = ItemPickupChangeFlags + local cf = ChangeFlags:new(pars) -function ItemPickupChangeFlags:_new(pars) - local ipcf + cf:add_triggerer( + DgnTriggerer:new { + type = "feat_change", + target = final_feat + } + ) - if pars then - ipcf = ChangeFlags:new(pars) - else - ipcf = ChangeFlags:_new() - end - - setmetatable(ipcf, self) - self.__index = self - - return ipcf -end - -function ItemPickupChangeFlags:new(pars) - pars = pars or { } - - if not pars.item then - error("No item name provided.") - end - - local ipcf = self:_new(pars) - ipcf.item = pars.item - - return ipcf -end - -function ItemPickupChangeFlags:activate(marker) - dgn.register_listener(dgn.dgn_event_type('item_pickup'), marker, - marker:pos()) - dgn.register_listener(dgn.dgn_event_type('item_moved'), marker, - marker:pos()) + return cf end -function ItemPickupChangeFlags:event(marker, ev) - local obj_idx = ev:arg1() - local it = dgn.item_from_index(obj_idx) - - if not it then - error("ItemPickupChangeFlags:event() didn't get a valid item index") - end - - if item.name(it) == self.item then - local picked_up = ev:type() == dgn.dgn_event_type('item_pickup') - if picked_up then - ChangeFlags.do_change(self, marker) - dgn.remove_listener(marker, marker:pos()) - dgn.remove_marker(marker) - else - dgn.remove_listener(marker, marker:pos()) - marker:move(ev:dest()) - self:activate(marker) - end - end -end +function item_pickup_change_flags(pars) + local item = pars.item or pars.target -function ItemPickupChangeFlags:write(marker, th) - ChangeFlags.write(self, marker, th) - file.marshall(th, self.item) -end + pars.item = nil + pars.target = nil -function ItemPickupChangeFlags:read(marker, th) - ChangeFlags.read(self, marker, th) - self.item = file.unmarshall_string(th) - setmetatable(self, ItemPickupChangeFlags) + local cf = ChangeFlags:new(pars) - return self -end + cf:add_triggerer( + DgnTriggerer:new { + type = "item_pickup", + target = item + } + ) -function item_pickup_change_flags(pars) - return ItemPickupChangeFlags:new(pars) + return cf end diff --git a/crawl-ref/source/dat/clua/lm_monst.lua b/crawl-ref/source/dat/clua/lm_monst.lua index f26e73e89b..539b7b140b 100644 --- a/crawl-ref/source/dat/clua/lm_monst.lua +++ b/crawl-ref/source/dat/clua/lm_monst.lua @@ -3,11 +3,12 @@ -- Create a monster on certain events -------------------------------------------------------------------------- --------------------------------------------------------------------------------------- --- This marker creates a monster on certain events. It uses the following parameters: +------------------------------------------------------------------------------- +-- This marker creates a monster on certain events. It uses the following +-- parameters: -- --- * death_monster: The name of the monster who's death triggers the creation of --- the new monster. +-- * death_monster: The name of the monster who's death triggers the creation +-- of the new monster. -- -- * new_monster: The name of the monster to create. -- @@ -20,30 +21,21 @@ -- -- NOTE: If the feature where the marker is isn't habitable by the new monster, -- the feature will be changed to the monster's primary habitat. --------------------------------------------------------------------------------------- +------------------------------------------------------------------------------- -- TODO: -- * Place more than one monster. -- * Place monster displaced from marker. +-- * Be triggered more than once. -MonsterOnTrigger = { CLASS = "MonsterOnTrigger" } -MonsterOnTrigger.__index = MonsterOnTrigger +require('clua/lm_trig.lua') -function MonsterOnTrigger:_new() - local pm = { } - setmetatable(pm, self) - self.__index = self - - return pm -end +MonsterOnTrigger = util.subclass(Triggerable) +MonsterOnTrigger.CLASS = "MonsterOnTrigger" function MonsterOnTrigger:new(pars) pars = pars or { } - if not pars.death_monster or pars.death_monster == "" then - error("Must provide death_monster") - end - if not pars.new_monster or pars.new_monster == "" then error("Must provide new_monster") end @@ -51,14 +43,15 @@ function MonsterOnTrigger:new(pars) pars.message_seen = pars.message_seen or pars.message or "" pars.message_unseen = pars.message_unseen or pars.message or "" - local pm = self:_new() - pm.message_seen = pars.message_seen - pm.message_unseen = pars.message_unseen - pm.death_monster = pars.death_monster - pm.new_monster = pars.new_monster - pm.props = pars + local mot = self.super.new(self) - return pm + mot.message_seen = pars.message_seen + mot.message_unseen = pars.message_unseen + mot.death_monster = pars.death_monster + mot.new_monster = pars.new_monster + mot.props = pars + + return mot end function MonsterOnTrigger:property(marker, pname) @@ -66,53 +59,71 @@ function MonsterOnTrigger:property(marker, pname) end function MonsterOnTrigger:write(marker, th) - lmark.marshall_table(th, self) + MonsterOnTrigger.super.write(self, marker, th) + + file.marshall(th, self.message_seen) + file.marshall(th, self.message_unseen) + file.marshall(th, self.new_monster) + lmark.marshall_table(th, self.props) end function MonsterOnTrigger:read(marker, th) - return MonsterOnTrigger:new(lmark.unmarshall_table(th)) -end + MonsterOnTrigger.super.read(self, marker, th) + + self.message_seen = file.unmarshall_string(th) + self.message_unseen = file.unmarshall_string(th) + self.new_monster = file.unmarshall_string(th) + self.props = lmark.unmarshall_table(th) -function MonsterOnTrigger:activate(marker) - dgn.register_listener(dgn.dgn_event_type('monster_dies'), marker) + setmetatable(self, MonsterOnTrigger) + + return self end -function MonsterOnTrigger:event(marker, ev) - local midx = ev:arg1() - local mons = dgn.mons_from_index(midx) +function MonsterOnTrigger:on_trigger(triggerer, marker, ev) + local x, y = marker:pos() + local you_x, you_y = you.pos() + + if x == you_x and y == you_y then + return + end - if not mons then - error("MonsterOnTrigger:event() didn't get a valid monster index") + if dgn.mons_at(x, y) then + return end - if mons.name == self.death_monster then - local x, y = marker:pos() - local you_x, you_y = you.pos() - - if x == you_x and y == you_y then - return - end - - -- you.losight() seems to be necessary if the player has been moved by - -- a wizard command and then the marker triggered by another wizard - -- command, since then no turns will have been taken and the LOS info - -- won't have been updated. - you.losight() - local see_cell = you.see_cell(x, y) - - if (not dgn.create_monster(x, y, self.new_monster)) then - return - elseif self.message_seen ~= "" and see_cell then - crawl.mpr(self.message_seen) - elseif self.message_unseen ~= "" and not see_cell then - crawl.mpr(self.message_unseen) - end - - dgn.remove_listener(marker) - dgn.remove_marker(marker) + -- you.losight() seems to be necessary if the player has been moved by + -- a wizard command and then the marker triggered by another wizard + -- command, since then no turns will have been taken and the LOS info + -- won't have been updated. + you.losight() + local see_cell = you.see_cell(x, y) + + if (not dgn.create_monster(x, y, self.new_monster)) then + return + elseif self.message_seen ~= "" and see_cell then + crawl.mpr(self.message_seen) + elseif self.message_unseen ~= "" and not see_cell then + crawl.mpr(self.message_unseen) end + + self:remove(marker) end -function monster_on_trigger(pars) - return MonsterOnTrigger:new(pars) +function monster_on_death(pars) + local death_monster = pars.death_monster or pars.target + + pars.death_monster = nil + pars.target = nil + + local mod = MonsterOnTrigger:new(pars) + + mod:add_triggerer( + DgnTriggerer:new { + type = "monster_dies", + target = death_monster + } + ) + + return mod end diff --git a/crawl-ref/source/dat/clua/lm_trig.lua b/crawl-ref/source/dat/clua/lm_trig.lua new file mode 100644 index 0000000000..f435fd2424 --- /dev/null +++ b/crawl-ref/source/dat/clua/lm_trig.lua @@ -0,0 +1,352 @@ +------------------------------------------------------------------------------ +-- dungeon.lua: +-- DgnTriggerers and triggerables: +-- +-- This is similar to the overvable/observer design pattern: a triggerable +-- class which does something and a triggerrer which sets it off. As an +-- example, the ChangeFlags class (clua/lm_flags.lua), rather than having +-- three subclasses (for monster death, feature change and item pickup) +-- needs no subclasses, but is just one class which is given triggerers +-- which listen for different events. Additionally, new types of triggerers +-- can be developed and used without have to update the ChangeFlags code. +-- +-- Unlike with the overvable/observer design pattern, each triggerer is +-- associated with a signle triggerable, rather than there being one observable +-- and multiple observers, since each triggerer might have a data payload which +-- is meant to be different for each triggerable. +-- +-- A triggerable class just needs to subclass Triggerable and define an +-- "on_trigger" method. +------------------------------------------------------------------------------ + +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) + + -- XXX: Are coordinated passed around as single objects? + 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 + -- We'll be handling the de-serialization of the triggerer, so we need to + -- save the class name. + 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 + -- Hack to let triggerer classes de-serialize themselves. + local trig_class = file.unmarshall_string(th) + + -- _G is the global symbol table, and the class name of the triggerer is + -- the name of that class's class object + 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 + +------------------------------------------------------------------------------- +-- NOTE: The CLASS string of a triggerer class *MUST* be exactly the same as +-- the triggerer class name, or it won't be able to deserialize properly. +-- +-- NOTE: A triggerer shouldn't store a reference to the triggerable it +-- belongs to, and if it does then it must not save/restore that reference. +------------------------------------------------------------------------------- + +-- DgnTriggerer listens for dungeon events of these types: +-- +-- * monster_dies: Waits for a monster to die. Needs the parameter +-- "target", who's value is the name of the monster who's death +-- we're wating for. Doesn't matter where the triggerable/marker +-- is placed. +-- +-- * feat_change: Waits for a cell's feature to change. Accepts the +-- optional parameter "target", which if set delays the trigger +-- until the feature the cell turns into contains the target as a +-- substring. The triggerable/marker must be placed on top of the +-- cell who's feature you wish to monitor. +-- +-- * item_moved: Wait for an item to move from one cell to another. +-- Needs the parameter "target", who's value is the name of the +-- item that is being tracked. The triggerable/marker must be placed +-- on top of the cell containing the item. +-- +-- * item_pickup: Wait for an item to be picked up. Needs the parameter +-- "target", who's value is the name of the item that is being tracked. +-- The triggerable/marker must be placed on top of the cell containing +-- the item. Automatically takes care of the item moving from one +-- square to another without being picked up. + +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 + -- Automatically move the triggerable if the item we're watching is moved + -- before it it's picked up. + 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 + -- We only exist to move the triggerable if the item moves + 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) + -- Will always be "dgn_event", so we don't need to save it. + 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 diff --git a/crawl-ref/source/dat/clua/luamark.lua b/crawl-ref/source/dat/clua/luamark.lua index 43ec7f94ae..d987e88ef1 100644 --- a/crawl-ref/source/dat/clua/luamark.lua +++ b/crawl-ref/source/dat/clua/luamark.lua @@ -3,6 +3,8 @@ -- Lua map marker handling. ------------------------------------------------------------------------------ +require('clua/lm_trig.lua') + require('clua/lm_pdesc.lua') require('clua/lm_1way.lua') require('clua/lm_timed.lua') diff --git a/crawl-ref/source/dat/clua/util.lua b/crawl-ref/source/dat/clua/util.lua index 4894f1fc67..1ed3670172 100644 --- a/crawl-ref/source/dat/clua/util.lua +++ b/crawl-ref/source/dat/clua/util.lua @@ -306,3 +306,23 @@ function table_to_string(table, depth) return str end + +-- Copied from http://lua-users.org/wiki/CopyTable +function util.copy_table(object) + local lookup_table = {} + local function _copy(object) + if type(object) ~= "table" then + return object + elseif lookup_table[object] then + return lookup_table[object] + end + local new_table = {} + lookup_table[object] = new_table + for index, value in pairs(object) do + new_table[_copy(index)] = _copy(value) + end + return setmetatable(new_table, getmetatable(object)) + end + return _copy(object) +end + diff --git a/crawl-ref/source/dat/hells.des b/crawl-ref/source/dat/hells.des index 3eefbf5c19..6122bc4027 100644 --- a/crawl-ref/source/dat/hells.des +++ b/crawl-ref/source/dat/hells.des @@ -454,7 +454,7 @@ SUBST: 4 = 4:20 7 SUBST: 8 = 8o COLOUR: o : cyan : dis_setup(_G) -MARKER: o = lua:monster_on_trigger { \ +MARKER: o = lua:monster_on_death { \ death_monster="Dispater", new_monster="generate_awake iron golem", \ message_seen="The iron statue comes to life!", \ message_unseen="You hear a grinding sound.", \ diff --git a/crawl-ref/source/dgnevent.h b/crawl-ref/source/dgnevent.h index 6b37744583..8d77d03b96 100644 --- a/crawl-ref/source/dgnevent.h +++ b/crawl-ref/source/dgnevent.h @@ -28,7 +28,15 @@ enum dgn_event_type DET_ITEM_PICKUP = 0x0200, DET_ITEM_MOVED = 0x0400, DET_FEAT_CHANGE = 0x0800, - DET_WALL_HIT = 0x1000 + DET_WALL_HIT = 0x1000, + + DET_GLOBAL_MASK = DET_TURN_ELAPSED | DET_LEAVING_LEVEL + | DET_ENTERING_LEVEL | DET_ENTERED_LEVEL + | DET_MONSTER_DIED, + + DET_POSITION_MASK = DET_MONSTER_MOVED | DET_PLAYER_MOVED + | DET_PLAYER_IN_LOS | DET_ITEM_PICKUP + | DET_ITEM_MOVED | DET_FEAT_CHANGE | DET_WALL_HIT }; class dgn_event diff --git a/crawl-ref/source/l_dgnevt.cc b/crawl-ref/source/l_dgnevt.cc index c379bad317..f6d1b56aeb 100644 --- a/crawl-ref/source/l_dgnevt.cc +++ b/crawl-ref/source/l_dgnevt.cc @@ -119,9 +119,33 @@ static int dgn_dgn_event(lua_State *ls) return (retvals); } +static dgn_event_type dgn_param_to_event_type(lua_State *ls, int n) +{ + if (lua_isnumber(ls, n)) + return (static_cast<dgn_event_type>(luaL_checkint(ls, n))); + else if (lua_isstring(ls, n)) + return dgn_event_type_by_name(lua_tostring(ls, n)); + else + return (DET_NONE); +} + +static int dgn_dgn_event_is_global(lua_State *ls) +{ + lua_pushboolean(ls, dgn_param_to_event_type(ls, 1) & DET_GLOBAL_MASK); + return (1); +} + +static int dgn_dgn_event_is_position(lua_State *ls) +{ + lua_pushboolean(ls, dgn_param_to_event_type(ls, 1) & DET_POSITION_MASK); + return (1); +} + const struct luaL_reg dgn_event_dlib[] = { -{ "dgn_event_type", dgn_dgn_event }, +{ "dgn_event_type", dgn_dgn_event }, +{ "dgn_event_is_global", dgn_dgn_event_is_global }, +{ "dgn_event_is_position", dgn_dgn_event_is_position}, { NULL, NULL } }; |