summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source/dat/clua
diff options
context:
space:
mode:
authorMatthew Cline <zelgadis@sourceforge.net>2009-11-04 21:49:19 -0800
committerMatthew Cline <zelgadis@sourceforge.net>2009-11-04 21:51:35 -0800
commitc73c1dad0a1d80a014ef59087aeee9f0e6171cf2 (patch)
tree3c8bfc0b1882d6df35fede06b3b629dee1b104bc /crawl-ref/source/dat/clua
parent1c4f4dd987fdfe1462aef78550f46ac1f46adf26 (diff)
downloadcrawl-ref-c73c1dad0a1d80a014ef59087aeee9f0e6171cf2.tar.gz
crawl-ref-c73c1dad0a1d80a014ef59087aeee9f0e6171cf2.zip
Slave/master handling in the Triggerable class
The Triggerable class can now handle master/slave marker logic. See dis_mu in hells.des for an example.
Diffstat (limited to 'crawl-ref/source/dat/clua')
-rw-r--r--crawl-ref/source/dat/clua/lm_flags.lua6
-rw-r--r--crawl-ref/source/dat/clua/lm_monst.lua6
-rw-r--r--crawl-ref/source/dat/clua/lm_trig.lua127
3 files changed, 121 insertions, 18 deletions
diff --git a/crawl-ref/source/dat/clua/lm_flags.lua b/crawl-ref/source/dat/clua/lm_flags.lua
index 3a2f3e1b5b..c6b93b7a2b 100644
--- a/crawl-ref/source/dat/clua/lm_flags.lua
+++ b/crawl-ref/source/dat/clua/lm_flags.lua
@@ -80,7 +80,7 @@ function ChangeFlags:new(pars)
cf.level_flags = pars.level_flags
cf.branch_flags = pars.branch_flags
cf.msg = pars.msg
- cf.props = { flag_group = pars.group }
+ cf.props = util.append( cf.props, { flag_group = pars.group } )
return cf
end
@@ -120,10 +120,6 @@ function ChangeFlags:on_trigger(triggerer, marker, ev)
return true, false
end
-function ChangeFlags:property(marker, pname)
- return self.props[pname] or ''
-end
-
function ChangeFlags:write(marker, th)
ChangeFlags.super.write(self, marker, th)
diff --git a/crawl-ref/source/dat/clua/lm_monst.lua b/crawl-ref/source/dat/clua/lm_monst.lua
index 539b7b140b..73b32cbc3c 100644
--- a/crawl-ref/source/dat/clua/lm_monst.lua
+++ b/crawl-ref/source/dat/clua/lm_monst.lua
@@ -49,15 +49,11 @@ function MonsterOnTrigger:new(pars)
mot.message_unseen = pars.message_unseen
mot.death_monster = pars.death_monster
mot.new_monster = pars.new_monster
- mot.props = pars
+ mot.props = util.append( mot.props, pars)
return mot
end
-function MonsterOnTrigger:property(marker, pname)
- return self.props[pname] or ''
-end
-
function MonsterOnTrigger:write(marker, th)
MonsterOnTrigger.super.write(self, marker, th)
diff --git a/crawl-ref/source/dat/clua/lm_trig.lua b/crawl-ref/source/dat/clua/lm_trig.lua
index 8431fe58b3..a37a3aa88a 100644
--- a/crawl-ref/source/dat/clua/lm_trig.lua
+++ b/crawl-ref/source/dat/clua/lm_trig.lua
@@ -2,7 +2,7 @@
-- lm_trig.lua:
-- DgnTriggerers and triggerables:
--
--- This is similar to the overvable/observer design pattern: a triggerable
+-- This is similar to the observable/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)
@@ -17,22 +17,53 @@
--
-- A triggerable class just needs to subclass Triggerable and define an
-- "on_trigger" method.
+--
+-- If a triggerable marker has the property "master_name" with the value
+-- "FOO", then when triggered on_trigger() will be called at each marker
+-- on the level which has the property "slaved_to" equal to "FOO". A
+-- master marker can be slaved to itself to cause on_trigger() to be called
+-- at it's location. If the master marker has the property
+-- "single_random_slave" set to anythinb but the empty string ("") then
+-- on each triggering only a single, randomly chosen slave will have
+-- on_trigger() called.
+--
+-- on_trigger() shouldn't have to worry about the master/slave business,
+-- and should have the same code regardless of whether or not it's a
+-- master or just a plain triggerable. If on_trigger() calls
+-- self:remove() while it's acting on a slave marker then the slave marker
+-- will be removed, and the master marker will only be removed when all
+-- slaves are gone.
------------------------------------------------------------------------------
Triggerable = { CLASS = "Triggerable" }
Triggerable.__index = Triggerable
-function Triggerable:new()
+function Triggerable:new(props)
+ props = props or {}
+
local tr = { }
setmetatable(tr, self)
self.__index = self
+ tr.props = props
tr.triggerers = { }
tr.dgn_trigs_by_type = { }
return tr
end
+function Triggerable:unmangle(x)
+ if x and type(x) == 'function' then
+ return x(self)
+ else
+ return x
+ end
+end
+
+function Triggerable:property(marker, pname)
+ return self:unmangle(self.props[pname] or '')
+end
+
function Triggerable:add_triggerer(triggerer)
if not triggerer.type then
error("triggerer has no type")
@@ -88,6 +119,11 @@ function Triggerable:remove(marker)
error("Trigerrable already removed")
end
+ if self.calling_slaves then
+ self.want_remove = true
+ return
+ end
+
self:remove_all_triggerers(marker)
dgn.remove_marker(marker)
@@ -144,7 +180,78 @@ function Triggerable:event(marker, ev)
end
end
+function Triggerable:do_trigger(triggerer, marker, ev)
+ local master_name = self:property(marker, "master_name")
+
+ if master_name == "" then
+ self:on_trigger(triggerer, marker, ev)
+ return
+ end
+
+ -- NOTE: The master marker can be slaved to itself.
+ local slaves =
+ dgn.find_markers_by_prop("slaved_to", master_name)
+
+ -- Pretend that the master marker is gone if it asked to be removed.
+ if self.master_removed then
+ for i = #slaves, 1, -1 do
+ if slaves[i] == marker then
+ table.remove(slaves, i)
+ end
+ end
+ end
+
+ -- If all slaves are gone, we're done.
+ if #slaves == 0 then
+ self:remove(marker)
+ return
+ end
+
+ local num_slaves = #slaves
+
+ if self:property("single_random_slave") ~= '' then
+ slaves = { slaves[ crawl.random2(#slaves) + 1 ] }
+ end
+
+ local num_want_remove = 0
+ self.calling_slaves = true
+ for _, slave_marker in ipairs(slaves) do
+ self.want_remove = false
+
+ self:on_trigger(triggerer, slave_marker, ev)
+
+ if self.want_remove then
+ num_want_remove = num_want_remove + 1
+
+ -- XXX: hack: don't remove ourself (the master marker) until the end.
+ if slave_marker == marker then
+ self.master_removed = true
+ else
+ triggerer:remove(self, slave_marker)
+ dgn.remove_marker(slave_marker)
+ end
+ end
+
+ self.want_remove = false
+ end
+ self.calling_slaves = false
+
+ if num_want_remove >= num_slaves then
+ -- Make sure they're really all gone.
+ slaves =
+ dgn.find_markers_by_prop("slaved_to", master_name)
+
+ if #slaves == 0
+ or (self.master_removed and #slaves == 1 and slaves[1] == marker)
+ then
+ self:remove(marker)
+ end
+ end
+end
+
function Triggerable:write(marker, th)
+ file.marshall_meta(th, self.master_removed)
+
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
@@ -154,9 +261,12 @@ function Triggerable:write(marker, th)
end
lmark.marshall_table(th, self.dgn_trigs_by_type)
+ lmark.marshall_table(th, self.props)
end
function Triggerable:read(marker, th)
+ self.master_removed = file.unmarshall_meta(th)
+
self.triggerers = {}
local num_trigs = file.unmarshall_number(th)
@@ -171,6 +281,7 @@ function Triggerable:read(marker, th)
end
self.dgn_trigs_by_type = lmark.unmarshall_table(th)
+ self.props = lmark.unmarshall_table(th)
setmetatable(self, Triggerable)
return self
@@ -373,7 +484,7 @@ function DgnTriggerer:monster_dies(triggerable, marker, ev)
end
if mons.name == self.target then
- triggerable:on_trigger(self, marker, ev)
+ triggerable:do_trigger(self, marker, ev)
end
end
@@ -384,7 +495,7 @@ function DgnTriggerer:feat_change(triggerable, marker, ev)
return
end
end
- triggerable:on_trigger(self, marker, ev)
+ triggerable:do_trigger(self, marker, ev)
end
function DgnTriggerer:item_moved(triggerable, marker, ev)
@@ -400,7 +511,7 @@ function DgnTriggerer:item_moved(triggerable, marker, ev)
-- We only exist to move the triggerable if the item moves
triggerable:move(marker, ev:dest())
else
- triggerable:on_trigger(self, marker, ev)
+ triggerable:do_trigger(self, marker, ev)
end
end
end
@@ -414,16 +525,16 @@ function DgnTriggerer:item_pickup(triggerable, marker, ev)
end
if item.name(it) == self.target then
- triggerable:on_trigger(self, marker, ev)
+ triggerable:do_trigger(self, marker, ev)
end
end
function DgnTriggerer:player_move(triggerable, marker, ev)
- triggerable:on_trigger(self, marker, ev)
+ triggerable:do_trigger(self, marker, ev)
end
function DgnTriggerer:player_los(triggerable, marker, ev)
- triggerable:on_trigger(self, marker, ev)
+ triggerable:do_trigger(self, marker, ev)
end
-------------------