diff options
-rw-r--r-- | crawl-ref/source/clua.cc | 11 | ||||
-rw-r--r-- | crawl-ref/source/dat/bazaar.des | 11 | ||||
-rw-r--r-- | crawl-ref/source/dat/clua/lm_pdesc.lua | 12 | ||||
-rw-r--r-- | crawl-ref/source/dat/clua/lm_timed.lua | 2 | ||||
-rw-r--r-- | crawl-ref/source/dat/clua/lm_tmsg.lua | 191 | ||||
-rw-r--r-- | crawl-ref/source/dat/clua/util.lua | 51 | ||||
-rw-r--r-- | crawl-ref/source/dat/clua/ziggurat.lua | 8 | ||||
-rw-r--r-- | crawl-ref/source/dat/database/monspeak.txt | 2 | ||||
-rw-r--r-- | crawl-ref/source/dat/lab.des | 13 | ||||
-rw-r--r-- | crawl-ref/source/dat/sewer.des | 39 | ||||
-rw-r--r-- | crawl-ref/source/directn.cc | 16 | ||||
-rw-r--r-- | crawl-ref/source/directn.h | 5 | ||||
-rw-r--r-- | crawl-ref/source/libutil.cc | 4 |
13 files changed, 262 insertions, 103 deletions
diff --git a/crawl-ref/source/clua.cc b/crawl-ref/source/clua.cc index 84b164d97b..5273907367 100644 --- a/crawl-ref/source/clua.cc +++ b/crawl-ref/source/clua.cc @@ -2149,6 +2149,16 @@ static int crawl_split(lua_State *ls) return (1); } +static int _crawl_grammar(lua_State *ls) +{ + description_level_type ndesc = DESC_PLAIN; + if (lua_isstring(ls, 2)) + ndesc = description_type_by_name(lua_tostring(ls, 2)); + PLUARET(string, + thing_do_grammar(ndesc, false, + false, luaL_checkstring(ls, 1)).c_str()); +} + static int crawl_article_a(lua_State *ls) { const char *s = luaL_checkstring(ls, 1); @@ -2296,6 +2306,7 @@ static const struct luaL_reg crawl_lib[] = { "message_filter", crawl_message_filter }, { "trim", crawl_trim }, { "split", crawl_split }, + { "grammar", _crawl_grammar }, { "article_a", crawl_article_a }, { "game_started", crawl_game_started }, { "err_trace", crawl_err_trace }, diff --git a/crawl-ref/source/dat/bazaar.des b/crawl-ref/source/dat/bazaar.des index b63caea014..a2a5ca73b5 100644 --- a/crawl-ref/source/dat/bazaar.des +++ b/crawl-ref/source/dat/bazaar.des @@ -11,7 +11,16 @@ lua {{ function bazaar_portal() - local messager = bell_clock_msg { initmsg="You hear coins being counted." } + local messager = + timed_msg { + initmsg = { "You hear coins being counted.", + "An interdimensional caravan has stopped on this level " + .. "and set up a bazaar. Hurry and find its entrance before " + .. "they move on!" }, + finalmsg = "You hear the last, dying notes of the bell.", + verb = 'tolling', + noisemaker = 'a massive bell' + } local blow = 200 + 30*(40 - you.absdepth()) + crawl.random2(200) local bhigh = blow + crawl.random2(blow) + 100 if not crawl.one_chance_in(6) then diff --git a/crawl-ref/source/dat/clua/lm_pdesc.lua b/crawl-ref/source/dat/clua/lm_pdesc.lua index f2e5cff9b2..32ae8e49a8 100644 --- a/crawl-ref/source/dat/clua/lm_pdesc.lua +++ b/crawl-ref/source/dat/clua/lm_pdesc.lua @@ -24,12 +24,20 @@ function PortalDescriptor:read(marker, th) return self end +function PortalDescriptor:unmangle(x) + if x and type(x) == 'function' then + return x(self) + else + return x + end +end + function PortalDescriptor:feature_description(marker) - return self.props.desc + return self:unmangle(self.props.desc) end function PortalDescriptor:property(marker, pname) - return self.props and self.props[pname] or '' + return self:unmangle(self.props and self.props[pname] or '') end function portal_desc(props) diff --git a/crawl-ref/source/dat/clua/lm_timed.lua b/crawl-ref/source/dat/clua/lm_timed.lua index a70ec69156..c12ec8157f 100644 --- a/crawl-ref/source/dat/clua/lm_timed.lua +++ b/crawl-ref/source/dat/clua/lm_timed.lua @@ -108,4 +108,4 @@ end function timed_marker(pars) return TimedMarker:new(pars) -end +end
\ No newline at end of file diff --git a/crawl-ref/source/dat/clua/lm_tmsg.lua b/crawl-ref/source/dat/clua/lm_tmsg.lua index 1939e39bc1..564ced9a6b 100644 --- a/crawl-ref/source/dat/clua/lm_tmsg.lua +++ b/crawl-ref/source/dat/clua/lm_tmsg.lua @@ -6,37 +6,37 @@ TimedMessaging = { } TimedMessaging.__index = TimedMessaging -function TimedMessaging._new() - local m = { } - setmetatable(m, TimedMessaging) - return m -end +function TimedMessaging:new(m, nocheck) + m = m or { } + setmetatable(m, self) + self.__index = self -function TimedMessaging.new(pars) - pars = pars or { } - local m = TimedMessaging._new() - m.noisemaker = pars.noisemaker - m.verb = pars.verb - m.finalmsg = pars.finalmsg - m.ranges = pars.ranges - m.initmsg = pars.initmsg or '' - return m -end + if not nocheck then + if not m.messages then + assert(m.noisemaker, "No noisemaker specified") + assert(m.verb, "No verb specified") + end -function TimedMessaging:init(tmarker, cm, verbose) - local lab = dgn.grid(cm:pos()) == dgn.feature_number('enter_labyrinth') - if not self.noisemaker then - self.noisemaker = lab and "an ancient clock" or "a massive bell" + if m.visible and not m.messages then + error("No messages set for timer messager") + end end - self.verb = self.verb or (lab and 'ticking' or 'tolling') + return m +end - if not self.finalmsg then - self.finalmsg = lab and "last, dying ticks of the clock" - or "last, dying notes of the bell" +function TimedMessaging:channel() + if not self.sound_channel then + self.sound_channel = + crawl.msgch_num(self.visible and 'default' or 'sound') end + return self.sound_channel +end + +function TimedMessaging:init(tmarker, cm, verbose) + self.entity = tmarker.props.entity or tmarker.props.desc - if not self.ranges then + if not self.ranges and not self.visible then self.ranges = { { 5000, 'stately ' }, { 4000, '' }, { 2500, 'brisk ' }, { 1500, 'urgent ' }, { 0, 'frantic ' } } @@ -47,33 +47,73 @@ function TimedMessaging:init(tmarker, cm, verbose) self.check = 50 end - if verbose and #self.initmsg > 0 and you.hear_pos(cm:pos()) then - crawl.mpr(self.initmsg, "sound") - if lab then - crawl.mpr("Behold! There is an entrance to a minotaur's labyrinth on this level. Find the entrance quickly before it seals the gate!", - "sound") - else - crawl.mpr("An interdimensional caravan has stopped on this level and set up a bazaar. Hurry and find its entrance before they move on!", "sound") + if verbose and self.initmsg then + self:emit_message(cm, self.initmsg) + end +end + +function TimedMessaging:perceptible(cm) + if not cm then + return true + end + + if self.visible then + return you.see_grid(cm:pos()) + else + return you.hear_pos(cm:pos()) + end +end + +function TimedMessaging:emit_message(cm, msg) + if not msg or not self:perceptible(cm) then + return + end + + if type(msg) == 'table' then + util.foreach(msg, + function (m) + self:emit_message(cm, m) + end) + else + if #msg < 1 then + return end + + crawl.mpr(util.expand_entity(self.entity, msg), self:channel()) end end -function TimedMessaging:say_message(dur) - self.sound_channel = self.sound_channel or crawl.msgch_num('sound') - if dur <= 0 then - crawl.mpr("You hear the " .. self.finalmsg .. ".", self.sound_channel) +function TimedMessaging:proc_ranges(ranges, dur, fn) + if not ranges then return end - for _, chk in ipairs(self.ranges) do + for _, chk in ipairs(ranges) do if dur > chk[1] then - crawl.mpr("You hear the " .. chk[2] .. self.verb - .. " of " .. self.noisemaker .. ".", - self.sound_channel) + fn(chk, dur) break end end end +function TimedMessaging:say_message(cm, dur) + if dur <= 0 then + self:emit_message(cm, self.finalmsg) + return + end + + self:proc_ranges(self.ranges, dur, + function (chk) + self:emit_message(cm, + "You hear the " .. chk[2] .. self.verb + .. " of " .. self.noisemaker .. ".") + end) + + self:proc_ranges(self.messages, dur, + function (chk) + self:emit_message(cm, chk[2]) + end) +end + function TimedMessaging:event(luamark, cmarker, event) if luamark.dur < self.check or luamark.dur <= 0 then self.check = luamark.dur - 250 @@ -81,32 +121,69 @@ function TimedMessaging:event(luamark, cmarker, event) self.check = self.check - 250 end - if you.hear_pos(cmarker:pos()) then - self:say_message(luamark.dur) + if self:perceptible(cmarker) then + self:say_message(nil, luamark.dur) end end end function TimedMessaging:write(th) - file.marshall(th, self.check) - file.marshall(th, self.noisemaker) - file.marshall(th, self.verb) - file.marshall(th, self.initmsg) - file.marshall(th, self.finalmsg) - lmark.marshall_table(th, self.ranges) + lmark.marshall_table(th, self) end function TimedMessaging.read(th) - local tm = TimedMessaging._new() - tm.check = file.unmarshall_number(th) - tm.noisemaker = file.unmarshall_string(th) - tm.verb = file.unmarshall_string(th) - tm.initmsg = file.unmarshall_string(th) - tm.finalmsg = file.unmarshall_string(th) - tm.ranges = lmark.unmarshall_table(th) - return tm + return TimedMessaging:new(lmark.unmarshall_table(th)) end -function bell_clock_msg(pars) - return TimedMessaging.new(pars) +function timed_msg(pars) + return TimedMessaging:new(pars) end + +-- Accepts pairs of turns and messages used for a timer. For instance +-- timer_interval_messages(500, 'You feel vaguely uneasy.', +-- 250, 'You feel extremely uneasy.', +-- 100, 'You feel a primal terror.') +-- Will produce the first message when the timer has > 500 turns, the +-- second message when the timer has <= 500 turns and >250 turns, and so on. +-- Note that any given interval message will be repeated, usually every 50 +-- or 25 turns. +function timer_interval_messages(...) + local breakpoints = util.partition({ ... }, 2) + -- Expand turn breakpoints into tenths of a turn. + util.foreach(breakpoints, + function (brk) + brk[1] = brk[1] * 10 + end) + return breakpoints +end + +-- Accepts timer messages as with timer_interval_messages, but with no +-- explicit intervals. Instead, the total turn count is divided by the +-- number of messages to determine intervals. +function time_messages(total_turns, ...) + local messages = { ... } + + local n = #messages + + -- Each interval is 1.2 * the previous (lower) interval. + local inflate = 1.2 + + local function power_sum(n) + local sum = 1 + for i = 1, n - 1 do + sum = sum + inflate ^ i + end + return sum + end + + local base_interval = total_turns / power_sum(n) + + local res = { } + for i = 1, n - 1 do + local pow = n - i + total_turns = total_turns - base_interval * inflate ^ pow + table.insert(res, { math.floor(10 * total_turns), messages[i] } ) + end + table.insert(res, { 0, messages[n] }) + return res +end
\ No newline at end of file diff --git a/crawl-ref/source/dat/clua/util.lua b/crawl-ref/source/dat/clua/util.lua index c9d6a9af3c..f0c16dc537 100644 --- a/crawl-ref/source/dat/clua/util.lua +++ b/crawl-ref/source/dat/clua/util.lua @@ -18,6 +18,28 @@ function util.identity(x) return x end +-- Returns the sublist of elements at indices [istart, iend) of the +-- supplied list. +function util.slice(list, istart, iend) + if not iend then + iend = #list + 1 + end + + local res = { } + for i = istart, iend - 1 do + table.insert(res, list[i]) + end + return res +end + +function util.partition(list, slice, increment) + local res = { } + for i = 1, #list, increment or slice do + table.insert(res, util.slice(list, i, i + slice)) + end + return res +end + function util.curry(fn, ...) local params = { ... } if #params == 1 then @@ -51,14 +73,7 @@ end -- Creates a string of the elements in list joined by separator. function util.join(sep, list) - local res = "" - for i, val in ipairs(list) do - if i > 1 then - res = res .. sep - end - res = res .. val - end - return res + return table.concat(list, sep) end -- Creates a set (a map of keys to true) from the list supplied. @@ -70,10 +85,13 @@ function util.set(list) return set end -function util.catlist(...) - local res = { } +-- Appends the elements in any number of additional tables to the first table. +function util.append(table, ...) + local res = table local tables = { ... } - if #tables == 1 then + if #tables == 0 then + return res + elseif #tables == 1 and #res == 0 then return tables[1] else for _, tab in ipairs(tables) do @@ -85,6 +103,10 @@ function util.catlist(...) return res end +function util.catlist(...) + return util.append({ }, ...) +end + function util.cathash(...) local res = { } local tables = { ... } @@ -191,6 +213,13 @@ function util.random_weighted_from(weightfn, list) return chosen end +function util.expand_entity(entity, msg) + return string.gsub(msg, "$F%{(%w+)%}", + function (desc) + return crawl.grammar(entity, desc) + end) +end + ---------------------------------------------------------- util.Timer = { } diff --git a/crawl-ref/source/dat/clua/ziggurat.lua b/crawl-ref/source/dat/clua/ziggurat.lua index 63095862a5..d9a55c2402 100644 --- a/crawl-ref/source/dat/clua/ziggurat.lua +++ b/crawl-ref/source/dat/clua/ziggurat.lua @@ -376,14 +376,6 @@ local function ziggurat_create_loot_at(c) local nloot = depth nloot = nloot + crawl.random2(math.floor(nloot * zig().portal.amount / 10000)) - local function free_space_threshold(max) - local function is_free_space(p) - return dgn.grid(p.x, p.y) == dgn.fnum("floor") and - #dgn.items_at(p.x, p.y) <= max - end - return is_free_space - end - local function find_free_space(nspaces) local spaces = { } local function add_spaces(p) diff --git a/crawl-ref/source/dat/database/monspeak.txt b/crawl-ref/source/dat/database/monspeak.txt index 80ae1f879d..a16ee346a0 100644 --- a/crawl-ref/source/dat/database/monspeak.txt +++ b/crawl-ref/source/dat/database/monspeak.txt @@ -2226,7 +2226,7 @@ VISUAL:@The_monster@ grows dozens of eye stalks in order to get a better look at VISUAL:@The_monster@ splits into many small globs of multi-coloured light, then recombines. -VISUAL:@The_monster@ breifly grows a face disturbingly similar to your own. +VISUAL:@The_monster@ briefly grows a face disturbingly similar to your own. @The_monster@ ululates chillingly with its many mouths. diff --git a/crawl-ref/source/dat/lab.des b/crawl-ref/source/dat/lab.des index 3655a3f9b4..c6e08d78d5 100644 --- a/crawl-ref/source/dat/lab.des +++ b/crawl-ref/source/dat/lab.des @@ -15,7 +15,18 @@ TAGS: luniq_lab chance_lab transparent trowel_portal allow_dup extra # chance to 2.85%. CHANCE: 50 : 285 DEPTH: 12-27 -: messager = bell_clock_msg { initmsg="You hear a distant snort." } +{{ + local messager = + timed_msg { + initmsg = { "You hear a distant snort.", + "Behold! There is an entrance to a minotaur's labyrinth " + .. "on this level. Find the entrance quickly before " + .. "the gate is sealed!" }, + finalmsg = "You hear the last, dying ticks of the clock.", + verb = 'ticking', + noisemaker = 'an ancient clock' + } +}} MARKER: O = lua: timed_marker { \ low=400, high=600, msg=messager, floor = 'stone_arch' \ } diff --git a/crawl-ref/source/dat/sewer.des b/crawl-ref/source/dat/sewer.des index bc5f589e94..ce8fc647a4 100644 --- a/crawl-ref/source/dat/sewer.des +++ b/crawl-ref/source/dat/sewer.des @@ -15,20 +15,37 @@ {{ function sewer_portal(e) - e.marker([[O = lua:one_way_stair { desc = "A glowing drain", - dst = "sewer", - dstorigin = "in the sewers", - overmap = "glowing drain", - floor = "stone_arch" }]]) + local timeout_turns = crawl.random_range(1500, 2000) + + local messager = + timed_msg { + visible = true, + -- $F{xxx} will be substituted with the 'entity' property of the timed + -- marker, or with the desc property (if entity is not set). + messages = time_messages(timeout_turns, + "$F{The} is slowly rusting away.", + "$F{The} is rusting away.", + "$F{The} is quickly rusting away.", + "$F{The} is falling apart.") + } + + e.lua_marker('O', + timed_marker { + desc = "glowing drain", + entity = 'drain', + dst = "sewer", + dstorigin = "in the sewers", + overmap = "glowing drain", + turns = timeout_turns, + floor = "stone_arch", + msg = messager }) e.kfeat("O = enter_portal_vault") e.colour("O = lightgreen") end -}} -# Use the following line in destination maps after all SUBST's have taken place -# : sewer_colours(_G) -# Note that the function also defines < to be the exit portal. -{{ +-- Use the following line in destination maps after all SUBSTs +-- : sewer_colours(_G) +-- Note that the function also defines < to be the exit portal. function sewer_colours(e) e.kfeat("< = exit_portal_vault") e.colour("< = darkgrey") @@ -305,7 +322,7 @@ MONS: worm / nothing w:3 MONS: ooze / nothing w:2 # chances are good you'll find something to cross the deep water ITEM: scroll of fear / scroll of fog / scroll of teleportation w:50 / \ - scroll of blinking / scroll of identify / nothing + scroll of blinking / scroll of identify / nothing ITEM: potion of levitation w:50 / potion of invisibility / \ potion of might / nothing # possibly rather generous loot, if you get to the center diff --git a/crawl-ref/source/directn.cc b/crawl-ref/source/directn.cc index 276b60266c..ba3f2df750 100644 --- a/crawl-ref/source/directn.cc +++ b/crawl-ref/source/directn.cc @@ -2271,12 +2271,12 @@ void describe_floor() mpr("Beware, for starvation awaits!", MSGCH_EXAMINE); } -static std::string _feature_do_grammar(description_level_type dtype, - bool add_stop, - bool force_article, - std::string desc) +std::string thing_do_grammar(description_level_type dtype, + bool add_stop, + bool force_article, + std::string desc) { - if (add_stop) + if (add_stop && (desc.empty() || desc[desc.length() - 1] != '.')) desc += "."; if (dtype == DESC_PLAIN || (!force_article && isupper(desc[0]))) { @@ -2320,7 +2320,7 @@ std::string feature_description(dungeon_feature_type grid, if (bloody) desc += ", spattered with blood"; - return _feature_do_grammar(dtype, add_stop, grid_is_trap(grid), desc); + return thing_do_grammar(dtype, add_stop, grid_is_trap(grid), desc); } std::string raw_feature_description(dungeon_feature_type grid, @@ -2592,7 +2592,7 @@ std::string feature_description(const coord_def& where, bool bloody, if (bloody) desc += ", spattered with blood"; - return _feature_do_grammar(dtype, add_stop, false, desc); + return thing_do_grammar(dtype, add_stop, false, desc); } switch (grid) @@ -2606,7 +2606,7 @@ std::string feature_description(const coord_def& where, bool bloody, return (shop_name(where, add_stop)); case DNGN_ENTER_PORTAL_VAULT: - return (_feature_do_grammar( + return (thing_do_grammar( dtype, add_stop, false, _marker_feature_description(where))); default: diff --git a/crawl-ref/source/directn.h b/crawl-ref/source/directn.h index a422f0fc2a..4b0b5ae841 100644 --- a/crawl-ref/source/directn.h +++ b/crawl-ref/source/directn.h @@ -153,6 +153,11 @@ bool in_los(const coord_def &pos); bool in_vlos(int x, int y); bool in_vlos(const coord_def &pos); +std::string thing_do_grammar(description_level_type dtype, + bool add_stop, + bool force_article, + std::string desc); + std::string get_terse_square_desc(const coord_def &gc); void terse_describe_square(const coord_def &c, bool in_range = true); void full_describe_square(const coord_def &c); diff --git a/crawl-ref/source/libutil.cc b/crawl-ref/source/libutil.cc index 7d06e22c5f..5a34a0a825 100644 --- a/crawl-ref/source/libutil.cc +++ b/crawl-ref/source/libutil.cc @@ -341,9 +341,9 @@ std::string pluralise(const std::string &name, // knife -> knives return name.substr(0, name.length() - 2) + "ves"; } - else if (ends_with(name, "ff")) + else if (ends_with(name, "staff")) { - // staff -> staves + // staff -> staves, but not hippogriff -> hippogrives. return name.substr(0, name.length() - 2) + "ves"; } else if (ends_with(name, "f")) |