summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source
diff options
context:
space:
mode:
authordshaligram <dshaligram@c06c8d41-db1a-0410-9941-cceddc491573>2008-11-23 18:58:31 +0000
committerdshaligram <dshaligram@c06c8d41-db1a-0410-9941-cceddc491573>2008-11-23 18:58:31 +0000
commitbe8748fa444e6813e09ef959f5ee4b88b67dd68e (patch)
tree0ed8640d1756cbfbd02091d0c74d7b47a7b0eec8 /crawl-ref/source
parent1392155c0cb7acb6224a39611102e46460a06e5b (diff)
downloadcrawl-ref-be8748fa444e6813e09ef959f5ee4b88b67dd68e.tar.gz
crawl-ref-be8748fa444e6813e09ef959f5ee4b88b67dd68e.zip
More steps toward ziggurats.
git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@7553 c06c8d41-db1a-0410-9941-cceddc491573
Diffstat (limited to 'crawl-ref/source')
-rw-r--r--crawl-ref/source/abyss.cc4
-rw-r--r--crawl-ref/source/cloud.cc34
-rw-r--r--crawl-ref/source/clua.cc78
-rw-r--r--crawl-ref/source/clua.h2
-rw-r--r--crawl-ref/source/dat/clua/dungeon.lua105
-rw-r--r--crawl-ref/source/dat/clua/util.lua67
-rw-r--r--crawl-ref/source/dat/clua/ziggurat.lua247
-rw-r--r--crawl-ref/source/dungeon.cc19
-rw-r--r--crawl-ref/source/dungeon.h5
-rw-r--r--crawl-ref/source/food.cc11
-rw-r--r--crawl-ref/source/luadgn.cc200
-rw-r--r--crawl-ref/source/makeitem.cc4
-rw-r--r--crawl-ref/source/mapdef.cc1
-rw-r--r--crawl-ref/source/mapdef.h3
-rw-r--r--crawl-ref/source/mon-pick.cc4
-rw-r--r--crawl-ref/source/monplace.cc24
-rw-r--r--crawl-ref/source/monplace.h3
-rw-r--r--crawl-ref/source/traps.cc34
-rw-r--r--crawl-ref/source/travel.cc13
-rw-r--r--crawl-ref/source/travel.h4
20 files changed, 678 insertions, 184 deletions
diff --git a/crawl-ref/source/abyss.cc b/crawl-ref/source/abyss.cc
index 34a44c16ad..5f84370253 100644
--- a/crawl-ref/source/abyss.cc
+++ b/crawl-ref/source/abyss.cc
@@ -681,9 +681,7 @@ static bool _spawn_corrupted_servant_near(const coord_def &pos)
}
// Got a place, summon the beast.
- int level = 51;
- monster_type mons = pick_random_monster(level_id(LEVEL_ABYSS), level,
- level);
+ monster_type mons = pick_random_monster(level_id(LEVEL_ABYSS));
if (mons == MONS_PROGRAM_BUG)
return (false);
diff --git a/crawl-ref/source/cloud.cc b/crawl-ref/source/cloud.cc
index 5c1f6a7512..daed16067d 100644
--- a/crawl-ref/source/cloud.cc
+++ b/crawl-ref/source/cloud.cc
@@ -815,22 +815,7 @@ bool valid_fog_machine_data(fog_machine_data data)
int num_fogs_for_place(int level_number, const level_id &place)
{
if (level_number == -1)
- {
- switch(place.level_type)
- {
- case LEVEL_DUNGEON:
- level_number = absdungeon_depth(place.branch, place.depth);
- break;
- case LEVEL_ABYSS:
- level_number = 51;
- break;
- case LEVEL_PANDEMONIUM:
- level_number = 52;
- break;
- default:
- level_number = you.your_level;
- }
- }
+ level_number = place.absdepth();
switch(place.level_type)
{
@@ -865,22 +850,7 @@ fog_machine_data random_fog_for_place(int level_number, const level_id &place)
fog_machine_data data = {NUM_FOG_MACHINE_TYPES, CLOUD_NONE, -1, -1};
if (level_number == -1)
- {
- switch(place.level_type)
- {
- case LEVEL_DUNGEON:
- level_number = absdungeon_depth(place.branch, place.depth);
- break;
- case LEVEL_ABYSS:
- level_number = 51;
- break;
- case LEVEL_PANDEMONIUM:
- level_number = 52;
- break;
- default:
- level_number = you.your_level;
- }
- }
+ level_number = place.absdepth();
switch(place.level_type)
{
diff --git a/crawl-ref/source/clua.cc b/crawl-ref/source/clua.cc
index c0c6e6845f..fac00a74dd 100644
--- a/crawl-ref/source/clua.cc
+++ b/crawl-ref/source/clua.cc
@@ -32,6 +32,7 @@
#include "macro.h"
#include "mapdef.h"
#include "message.h"
+#include "monstuff.h"
#include "mon-util.h"
#include "newgame.h"
#include "output.h"
@@ -636,6 +637,8 @@ void CLua::init_lua()
lua_register(_state, "loadfile", _clua_loadfile);
lua_register(_state, "dofile", _clua_dofile);
+ execfile("clua/util.lua", true, true);
+
if (managed_vm)
{
lua_register(_state, "pcall", _clua_guarded_pcall);
@@ -945,6 +948,17 @@ void lua_set_exclusive_item(const item_def *item)
excl_item = item;
}
+void lua_push_items(lua_State *ls, int link)
+{
+ lua_newtable(ls);
+ int index = 0;
+ for ( ; link != NON_ITEM; link = mitm[link].link)
+ {
+ lua_pushlightuserdata(ls, &mitm[link]);
+ lua_rawseti(ls, -2, ++index);
+ }
+}
+
static int l_item_inventory(lua_State *ls)
{
lua_push_inv_items(ls);
@@ -2382,22 +2396,65 @@ struct MonsterWrap
long turn;
};
-static int l_mons_name(lua_State *ls, monsters *mons, const char *attr)
+#define MDEF(name) \
+ static int l_mons_##name(lua_State *ls, monsters *mons, \
+ const char *attr) \
+
+#define MDEFN(name, closure) \
+ static int l_mons_##name(lua_State *ls, monsters *mons, const char *attrs) \
+ { \
+ lua_pushlightuserdata(ls, mons); \
+ lua_pushcclosure(ls, l_mons_do_dismiss, 1); \
+ return (1); \
+ }
+
+#define ASSERT_DLUA \
+ do { \
+ if (CLua::get_vm(ls).managed_vm) \
+ luaL_error(ls, "Operation forbidden in end-user script"); \
+ } while (false)
+
+MDEF(name)
{
- lua_pushstring(ls, mons_type_name(mons->type, DESC_PLAIN).c_str());
- return (1);
+ PLUARET(string, mons_type_name(mons->type, DESC_PLAIN).c_str());
}
-static int l_mons_x(lua_State *ls, monsters *mons, const char *attr)
+MDEF(x)
{
- lua_pushnumber(ls, int(mons->pos().x) - int(you.pos().x));
- return (1);
+ PLUARET(number, int(mons->pos().x) - int(you.pos().x));
}
-static int l_mons_y(lua_State *ls, monsters *mons, const char *attr)
+MDEF(y)
{
- lua_pushnumber(ls, int(mons->pos().y) - int(you.pos().y));
- return (1);
+ PLUARET(number, int(mons->pos().y) - int(you.pos().y));
+}
+
+MDEF(hd)
+{
+ PLUARET(number, mons->hit_dice);
+}
+
+static int l_mons_do_dismiss(lua_State *ls)
+{
+ // dismiss is only callable from dlua, not from managed VMs (i.e.
+ // end-user scripts cannot dismiss monsters).
+ ASSERT_DLUA;
+ monsters *mons =
+ util_get_userdata<monsters>(ls, lua_upvalueindex(1));
+ if (mons->alive())
+ {
+ mons->flags |= MF_HARD_RESET;
+ monster_die(mons, KILL_DISMISSED, NON_MONSTER);
+ }
+ return (0);
+}
+
+MDEFN(dismiss, do_dismiss)
+
+MDEF(experience)
+{
+ ASSERT_DLUA;
+ PLUARET(number, exper_value(mons));
}
struct MonsAccessor
@@ -2411,6 +2468,9 @@ static MonsAccessor mons_attrs[] =
{ "name", l_mons_name },
{ "x" , l_mons_x },
{ "y" , l_mons_y },
+ { "hd" , l_mons_hd },
+ { "dismiss", l_mons_dismiss },
+ { "experience", l_mons_experience },
};
static int monster_get(lua_State *ls)
diff --git a/crawl-ref/source/clua.h b/crawl-ref/source/clua.h
index a2de0f4f2c..e1499675a8 100644
--- a/crawl-ref/source/clua.h
+++ b/crawl-ref/source/clua.h
@@ -280,6 +280,8 @@ class dgn_event;
void clua_push_map(lua_State *ls, map_def *map);
void clua_push_dgn_event(lua_State *ls, const dgn_event *devent);
+void lua_push_items(lua_State *ls, int link);
+
template <class T> T *clua_new_userdata(
lua_State *ls, const char *mt)
{
diff --git a/crawl-ref/source/dat/clua/dungeon.lua b/crawl-ref/source/dat/clua/dungeon.lua
index 66148a3708..2736e1f372 100644
--- a/crawl-ref/source/dat/clua/dungeon.lua
+++ b/crawl-ref/source/dat/clua/dungeon.lua
@@ -4,8 +4,8 @@
------------------------------------------------------------------------------
dgn.GXM, dgn.GYM = dgn.max_bounds()
-dgn.f_rockwall = dgn.feature_number("rock_wall")
-dgn.f_floor = dgn.feature_number("floor")
+
+dgn.f_map = { }
-- Table that will be saved in <foo>.sav.
dgn.persist = { }
@@ -18,6 +18,15 @@ function dgn_load_data(th)
dgn.persist = lmark.unmarshall_table(th) or { }
end
+function dgn.fnum(name)
+ local fnum = dgn.f_map[name]
+ if not fnum then
+ fnum = dgn.feature_number(name)
+ dgn.f_map[name] = fnum
+ end
+ return fnum
+end
+
-- Wraps a map_def into a Lua environment (a table) such that
-- functions run in the environment (with setfenv) can directly
-- address the map with function calls such as name(), tags(), etc.
@@ -34,7 +43,7 @@ function dgn_map_meta_wrap(map, tab)
if not meta then
meta = { }
-
+
local meta_meta = { __index = _G }
setmetatable(meta, meta_meta)
dgn._map_envs[name] = meta
@@ -94,7 +103,7 @@ function dgn.places_connected(map, map_glyph, test_connect, ...)
end
function dgn.any_glyph_connected(map, ...)
- return dgn.places_connected(map, dgn.gly_points,
+ return dgn.places_connected(map, dgn.gly_points,
dgn.any_point_connected, ...)
end
@@ -144,7 +153,7 @@ function dgn.fnum_map(map)
return fnmap
end
--- Replaces all features matching
+-- Replaces all features matching
function dgn.replace_feat(rmap)
local cmap = dgn.fnum_map(rmap)
@@ -159,6 +168,92 @@ function dgn.replace_feat(rmap)
end
end
+function dgn.adjacent_points(c, faccept)
+ local plist = { }
+
+ local compass = {
+ { 0, -1 }, { 1, 0 }, { 0, 1 }, { -1, 0 },
+ { -1, -1 }, { 1, -1 }, { 1, 1 }, { -1, 1 }
+ }
+
+ for _, cp in ipairs(compass) do
+ local p = { x = c.x + cp[1], y = c.y + cp[2] }
+ if dgn.in_bounds(p.x, p.y) and faccept(p) then
+ table.insert(plist, p)
+ end
+ end
+ return plist
+end
+
+function dgn.find_adjacent_point(c, fcondition, fpassable)
+ local mapped_points = { }
+
+ local function pstr(p)
+ return p.x .. "," .. p.y
+ end
+
+ local function seen(p)
+ return mapped_points[pstr(p)]
+ end
+
+ local function record(p, val)
+ mapped_points[pstr(p)] = val or 1
+ end
+
+ if not fpassable then
+ fpassable = function (p)
+ return dgn.is_passable(p.x, p.y)
+ end
+ end
+
+ local iter_points = { { }, { } }
+ local iter = 1
+ table.insert(iter_points[iter], c)
+
+ local function next_iter()
+ if iter == 1 then
+ return 2
+ else
+ return 1
+ end
+ end
+
+ local distance = 1
+ record(c, distance)
+
+ while #iter_points[iter] > 0 do
+ for _, p in ipairs(iter_points[iter]) do
+ if fcondition(p) then
+ return p
+ end
+
+ -- Add adjacent points to queue.
+ for _, np in ipairs(dgn.adjacent_points(p, fpassable)) do
+ if not seen(np) then
+ table.insert(iter_points[next_iter()], np)
+ record(np, distance + 1)
+ end
+ end
+ end
+ iter_points[iter] = { }
+ iter = next_iter()
+ distance = distance + 1
+ end
+
+ -- No suitable point.
+ return nil
+end
+
+function dgn.colour_map(fselect, colour)
+ for x = 0, dgn.GXM - 1 do
+ for y = 0, dgn.GYM - 1 do
+ if fselect(x, y) then
+ dgn.colour_at(x, y, colour)
+ end
+ end
+ end
+end
+
----------------------------------------------------------------------
-- Convenience functions for vaults.
diff --git a/crawl-ref/source/dat/clua/util.lua b/crawl-ref/source/dat/clua/util.lua
new file mode 100644
index 0000000000..0c327fd194
--- /dev/null
+++ b/crawl-ref/source/dat/clua/util.lua
@@ -0,0 +1,67 @@
+------------------------------------------------------------------------------
+-- util.lua
+-- Lua utilities.
+------------------------------------------------------------------------------
+
+util = { }
+
+function util.catlist(...)
+ local res = { }
+ local tables = { ... }
+ if #tables == 1 then
+ return tables[1]
+ else
+ for _, tab in ipairs(tables) do
+ for _, val in ipairs(tab) do
+ table.insert(res, val)
+ end
+ end
+ end
+ return res
+end
+
+function util.cathash(...)
+ local res = { }
+ local tables = { ... }
+ if #tables == 1 then
+ return tables[1]
+ else
+ for _, tab in ipairs(tables) do
+ for key, val in ipairs(tab) do
+ res[key] = val
+ end
+ end
+ end
+ return res
+end
+
+function util.map(fn, ...)
+ local lists = { ... }
+ local res = { }
+ if #lists == 0 then
+ return res
+ elseif #lists == 1 then
+ for _, val in ipairs(lists[1]) do
+ table.insert(res, fn(val))
+ end
+ else
+ for i = 1, #lists[1] do
+ local args = { }
+ for _, list in ipairs(lists) do
+ if not list[i] then
+ break
+ end
+ table.insert(args, list[i])
+ end
+ if #args < #lists then
+ break
+ end
+ table.insert(res, fn(unpack(args)))
+ end
+ end
+ return res
+end
+
+function util.random_from(list)
+ return list[ crawl.random2(#list) + 1 ]
+end \ No newline at end of file
diff --git a/crawl-ref/source/dat/clua/ziggurat.lua b/crawl-ref/source/dat/clua/ziggurat.lua
index 1b8439a0cf..8629eeabd3 100644
--- a/crawl-ref/source/dat/clua/ziggurat.lua
+++ b/crawl-ref/source/dat/clua/ziggurat.lua
@@ -17,18 +17,34 @@ function zig()
return dgn.persist.ziggurat
end
--- Returns a function that changes the depth in the ziggurat to the depth
--- specified.
-local function zig_depth_increment()
- return function (...)
- zig().depth = zig().depth + 1
- end
+local wall_colours = {
+ "blue", "red", "lightblue", "magenta", "green", "white"
+}
+
+local function wall_colour()
+ return util.random_from(wall_colours)
+end
+
+local function random_floor_colour()
+ return wall_colour()
end
function ziggurat_initializer()
local z = zig()
z.depth = 1
+
+ -- Any given ziggurat will use the same builder for all its levels.
z.builder = ziggurat_choose_builder()
+
+ z.colour = wall_colour()
+ z.level = { }
+end
+
+-- Returns a function that changes the depth in the ziggurat to the depth
+-- specified.
+function zig_depth_increment()
+ zig().depth = zig().depth + 1
+ zig().level = { }
end
-- Returns the current depth in the ziggurat.
@@ -84,24 +100,225 @@ end
-- Creates a Lua marker table that increments ziggurat depth.
local function zig_go_deeper()
return one_way_stair {
- onclimb = zig_depth_increment()
+ onclimb = zig_depth_increment
}
end
+local function map_area()
+ local base_area = 20 + 8 * zig_depth()
+ return 2 * base_area + crawl.random2(base_area)
+end
+
+local function clamp_in(val, low, high)
+ if val < low then
+ return low
+ elseif val > high then
+ return high
+ else
+ return val
+ end
+end
+
+local function clamp_in_bounds(x, y)
+ return clamp_in(x, 1, dgn.GXM - 2), clamp_in(y, 1, dgn.GYM - 2)
+end
+
+local function rectangle_dimensions()
+ local area = map_area()
+
+ local cx, cy = dgn.GXM / 2, dgn.GYM / 2
+
+ local asqrt = math.sqrt(area)
+ local b = crawl.random_range(1 + asqrt / 2, asqrt + 1)
+ local a = math.floor((area + b - 1) / b)
+
+ local a2 = math.floor(a / 2) + (a % 2);
+ local b2 = math.floor(b / 2) + (b % 2);
+ local x1, y1 = clamp_in_bounds(cx - a2, cy - b2)
+ local x2, y2 = clamp_in_bounds(cx + a2, cy + b2)
+ return x1, y1, x2, y2
+end
+
+local mons_populations = {
+ "Elf:7", "Orc:4", "Vault:8", "Slime:6",
+ "Snake:5", "Lair:10", "Tomb:3", "Crypt:5",
+ "Abyss", "Shoal:5", "Pan"
+}
+
+local function set_floor_colour(colour)
+ if not zig().level.floor_colour then
+ zig().level.floor_colour = colour
+ dgn.change_floor_colour(colour)
+ end
+end
+
+local function set_random_floor_colour()
+ set_floor_colour( random_floor_colour() )
+end
+
+local function mons_random_gen(x, y, nth)
+ set_random_floor_colour()
+ return dgn.create_monster(x, y, "place:" ..
+ util.random_from(mons_populations))
+end
+
+local function mons_drac_gen(x, y, nth)
+ set_random_floor_colour()
+ return dgn.create_monster(x, y, "random draconian")
+end
+
+local function mons_panlord_gen(x, y, nth)
+ set_random_floor_colour()
+ if nth == 1 then
+ return dgn.create_monster(x, y, "pandemonium lord band")
+ else
+ return dgn.create_monster(x, y, "place:Pan")
+ end
+end
+
+local mons_generators = {
+ mons_random_gen,
+ mons_drac_gen,
+ mons_panlord_gen
+}
+
+local function monster_creator_fn(arg)
+ if type(arg) == "string" then
+ local _, _, branch = string.find(arg, "^(%w+):")
+ return function (x, y, nth)
+ if branch then
+ set_floor_colour(dgn.br_floorcol(branch))
+ end
+
+ return dgn.create_monster(x, y, "place:" .. arg)
+ end
+ else
+ return arg
+ end
+end
+
+local monster_creators =
+ util.map(monster_creator_fn, util.catlist(mons_populations, mons_generators))
+
+local function ziggurat_vet_monster(fn)
+ return function (x, y, nth)
+ while true do
+ local mons = fn(x, y, nth)
+ if mons then
+ if mons.experience == 0 then
+ mons.dismiss()
+ else
+ -- Monster is ok!
+ return mons
+ end
+ end
+ end
+ end
+end
+
+local function choose_monster_set()
+ return ziggurat_vet_monster(util.random_from(monster_creators))
+end
+
+local function ziggurat_create_monsters(p)
+ local depth = zig_depth()
+ local hd_pool = depth * (depth + 8)
+
+ local function mons_place_p(point)
+ return not dgn.mons_at(point.x, point.y)
+ end
+
+ local mfn = choose_monster_set()
+ local nth = 1
+
+ -- No monsters
+ while hd_pool > 0 do
+ local place = dgn.find_adjacent_point(p, mons_place_p)
+ local mons = mfn(place.x, place.y, nth)
+
+ if mons then
+ nth = nth + 1
+ hd_pool = hd_pool - mons.hd
+ end
+ end
+end
+
+local function flip_rectangle(x1, y1, x2, y2)
+ local cx = math.floor((x1 + x2) / 2)
+ local cy = math.floor((y1 + y2) / 2)
+ local nx1 = cx + y1 - cy
+ local nx2 = cx + y2 - cy
+ local ny1 = cy + x1 - cx
+ local ny2 = cy + x2 - cx
+ return { nx1, ny1, nx2, ny2 }
+end
+
+local function ziggurat_create_loot(c)
+ local nloot = zig_depth()
+ local depth = zig_depth()
+
+ local function is_free_space(p)
+ return dgn.grid(p.x, p.y) == dgn.fnum("floor") and
+ #dgn.items_at(p.x, p.y) == 0
+ end
+
+ local function free_space_do(fn)
+ local p = dgn.find_adjacent_point(c, is_free_space)
+ if p then
+ fn(p)
+ end
+ end
+
+ for i = 1, nloot do
+ if crawl.one_chance_in(depth) then
+ for j = 1, 4 do
+ free_space_do(function (p)
+ dgn.create_item(p.x, p.y, "*", 20)
+ end)
+ end
+ else
+ free_space_do(function (p)
+ dgn.create_item(p.x, p.y, "|", 20)
+ end)
+ end
+ end
+end
+
local function ziggurat_rectangle_builder(e)
local grid = dgn.grid
- -- FIXME: Cool code goes here.
- local x1, y1 = 20, 20
- local x2, y2 = dgn.GXM - 20, dgn.GYM - 20
+ dgn.fill_area(0, 0, dgn.GXM - 1, dgn.GYM - 1, "stone_wall")
+
+ local x1, y1, x2, y2 = rectangle_dimensions()
dgn.fill_area(x1, y1, x2, y2, "floor")
- local my = math.floor((y1 + y2) / 2)
- zigstair(x1, my, "stone_arch", "stone_stairs_up_i")
- zigstair(x2, my, "stone_stairs_down_i", zig_go_deeper)
- grid(x2, my + 1, "exit_portal_vault")
+ dgn.fill_area(unpack( util.catlist(flip_rectangle(x1, y1, x2, y2),
+ { "floor" }) ) )
+
+ local cy = math.floor((y1 + y2) / 2)
+
+ local entry = { x = x1, y = cy }
+ local exit = { x = x2, y = cy }
+
+ if zig_depth() % 2 == 0 then
+ entry, exit = exit, entry
+ end
+
+ zigstair(entry.x, entry.y, "stone_arch", "stone_stairs_up_i")
+ zigstair(exit.x, exit.y, "stone_stairs_down_i", zig_go_deeper)
+ grid(exit.x, exit.y + 1, "exit_portal_vault")
+ grid(exit.x, exit.y - 1, "exit_portal_vault")
+
+ ziggurat_create_loot(exit)
+
+ --ziggurat_create_monsters(exit)
+
+ dgn.colour_map(function (x, y)
+ return dgn.grid(x, y) == dgn.fnum("stone_wall")
+ end,
+ zig().colour)
- crawl.mpr("Ziggurat depth is now " .. zig_depth())
+ crawl.mpr("Ziggurat depth is now " .. zig_depth(), "diagnostic")
end
----------------------------------------------------------------------
diff --git a/crawl-ref/source/dungeon.cc b/crawl-ref/source/dungeon.cc
index 9d8bc2c6f7..f78a65de55 100644
--- a/crawl-ref/source/dungeon.cc
+++ b/crawl-ref/source/dungeon.cc
@@ -4759,8 +4759,8 @@ static void _dgn_place_item_explicit(const item_spec &spec,
grd(where) = DNGN_FLOOR;
}
-static void _dgn_place_multiple_items(item_list &list,
- const coord_def& where, int level)
+void dgn_place_multiple_items(item_list &list,
+ const coord_def& where, int level)
{
const int size = list.size();
for (int i = 0; i < size; ++i)
@@ -4885,6 +4885,7 @@ bool dgn_place_monster(mons_spec &mspec,
const int mid = mspec.mid;
const bool m_generate_awake = (generate_awake || mspec.generate_awake);
const bool m_patrolling = (patrolling || mspec.patrolling);
+ const bool m_band = mspec.band;
const int mlev = mspec.mlevel;
if (mlev)
@@ -4924,7 +4925,7 @@ bool dgn_place_monster(mons_spec &mspec,
int lev = monster_level;
if (mspec.place.level_type == LEVEL_DUNGEON)
- lev = absdungeon_depth(mspec.place.branch, mspec.place.depth);
+ lev = mspec.place.absdepth();
if (mlev == -8)
lev = 4 + lev * 2;
@@ -4966,12 +4967,12 @@ bool dgn_place_monster(mons_spec &mspec,
if (m_patrolling)
mg.flags |= MG_PATROLLING;
+ if (m_band)
+ mg.flags |= MG_PERMIT_BANDS;
+
const int mindex = place_monster(mg, true);
- if (mindex != -1)
- {
- if (mspec.items.size() > 0)
- _dgn_give_mon_spec_items(mspec, mindex, mid, monster_level);
- }
+ if (mindex != -1 && mspec.items.size() > 0)
+ _dgn_give_mon_spec_items(mspec, mindex, mid, monster_level);
return (mindex != -1);
}
return (false);
@@ -5123,7 +5124,7 @@ static int _vault_grid( vault_placement &place,
_dgn_place_one_monster(place, mons, level_number, where);
item_list &items = mapsp->get_items();
- _dgn_place_multiple_items(items, where, level_number);
+ dgn_place_multiple_items(items, where, level_number);
return (altar_count);
}
diff --git a/crawl-ref/source/dungeon.h b/crawl-ref/source/dungeon.h
index 756c431ab3..ece814c54f 100644
--- a/crawl-ref/source/dungeon.h
+++ b/crawl-ref/source/dungeon.h
@@ -331,6 +331,11 @@ bool dgn_place_monster(mons_spec &mspec,
bool force_pos = false, bool generate_awake = false,
bool patrolling = false);
+class item_list;
+void dgn_place_multiple_items(item_list &list,
+ const coord_def& where,
+ int level);
+
bool set_level_flags(unsigned long flags, bool silent = false);
bool unset_level_flags(unsigned long flags, bool silent = false);
diff --git a/crawl-ref/source/food.cc b/crawl-ref/source/food.cc
index 14bbd41261..69a1cb036f 100644
--- a/crawl-ref/source/food.cc
+++ b/crawl-ref/source/food.cc
@@ -702,17 +702,6 @@ bool butchery(int which_corpse)
return (success);
}
-void lua_push_items(lua_State *ls, int link)
-{
- lua_newtable(ls);
- int index = 0;
- for ( ; link != NON_ITEM; link = mitm[link].link)
- {
- lua_pushlightuserdata(ls, &mitm[link]);
- lua_rawseti(ls, -2, ++index);
- }
-}
-
void lua_push_floor_items(lua_State *ls)
{
lua_push_items(ls, igrd(you.pos()));
diff --git a/crawl-ref/source/luadgn.cc b/crawl-ref/source/luadgn.cc
index 229fc9946d..60834c3c64 100644
--- a/crawl-ref/source/luadgn.cc
+++ b/crawl-ref/source/luadgn.cc
@@ -26,6 +26,7 @@
#include "mapmark.h"
#include "maps.h"
#include "misc.h"
+#include "mon-util.h"
#include "spl-util.h"
#include "stuff.h"
#include "tags.h"
@@ -315,6 +316,8 @@ std::string dlua_chunk::get_chunk_prefix(const std::string &sorig) const
#define MAPMARKER(ls, n, var) \
map_marker *var = *(map_marker **) luaL_checkudata(ls, n, MAPMARK_METATABLE)
+#define LUAFN(name) static int name(lua_State *ls)
+
static dungeon_feature_type _get_lua_feature(lua_State *ls, int idx)
{
dungeon_feature_type feat = (dungeon_feature_type)0;
@@ -336,15 +339,19 @@ static dungeon_feature_type _check_lua_feature(lua_State *ls, int idx)
return (f);
}
-#define COORDS(c, p1, p2) \
+#define GETCOORD(c, p1, p2, boundfn) \
coord_def c; \
c.x = luaL_checkint(ls, p1); \
c.y = luaL_checkint(ls, p2); \
- if (!in_bounds(c)) \
- luaL_error( \
+ if (!boundfn(c)) \
+ luaL_error( \
ls, \
- make_stringf("Point (%d,%d) is out of map bounds", \
- c.x, c.y).c_str());
+ make_stringf("Point (%d,%d) is out of bounds", \
+ c.x, c.y).c_str()); \
+ else ; \
+
+#define COORDS(c, p1, p2) \
+ GETCOORD(c, p1, p2, in_bounds)
#define FEAT(f, pos) \
dungeon_feature_type f = _check_lua_feature(ls, pos)
@@ -908,7 +915,7 @@ static int dgn_welcome(lua_State *ls)
static int dgn_grid(lua_State *ls)
{
- COORDS(c, 1, 2);
+ GETCOORD(c, 1, 2, map_bounds);
if (!lua_isnone(ls, 3))
{
@@ -1094,70 +1101,53 @@ static int dgn_get_rock_colour(lua_State *ls)
PLUARET(string, colour_to_str(env.rock_colour).c_str());
}
-static int dgn_change_floor_colour(lua_State *ls)
+static int _lua_colour(lua_State *ls, int ndx,
+ int forbidden_colour = -1)
{
- const char *s = luaL_checkstring(ls, 1);
- int colour = str_to_colour(s);
-
- if (colour < 0 || colour == BLACK)
+ if (lua_isnumber(ls, ndx))
+ return lua_tonumber(ls, ndx);
+ else if (const char *s = luaL_checkstring(ls, ndx))
{
- std::string error;
+ const int colour = str_to_colour(s);
- if (colour == BLACK)
- {
- error = "Can't set floor to black.";
- }
- else
+ if (colour < 0 || colour == forbidden_colour)
{
- error = "No such colour as '";
- error += s;
- error += "'";
+ std::string error;
+ if (colour == forbidden_colour)
+ error = std::string("Can't set floor to ") + s;
+ else
+ error = std::string("Unknown colour: '") + s + "'";
+ return luaL_argerror(ls, 1, error.c_str());
}
-
- luaL_argerror(ls, 1, error.c_str());
-
- return (0);
+ return (colour);
}
+ return luaL_argerror(ls, ndx, "Expected colour name or number");
+}
+static int dgn_change_floor_colour(lua_State *ls)
+{
+ const int colour = _lua_colour(ls, 1, BLACK);
env.floor_colour = (unsigned char) colour;
-
viewwindow(true, false);
-
return (0);
}
static int dgn_change_rock_colour(lua_State *ls)
{
- const char *s = luaL_checkstring(ls, 1);
- int colour = str_to_colour(s);
-
- if (colour < 0 || colour == BLACK)
- {
- std::string error;
-
- if (colour == BLACK)
- {
- error = "Can't set rock to black.";
- }
- else
- {
- error = "No such colour as '";
- error += s;
- error += "'";
- }
-
- luaL_argerror(ls, 1, error.c_str());
-
- return (0);
- }
-
+ const int colour = _lua_colour(ls, 1, BLACK);
env.rock_colour = (unsigned char) colour;
-
viewwindow(true, false);
-
return (0);
}
+static int dgn_colour_at(lua_State *ls)
+{
+ COORDS(c, 1, 2);
+ if (!lua_isnone(ls, 3))
+ env.grid_colours(c) = _lua_colour(ls, 3);
+ PLUARET(string, colour_to_str(env.grid_colours(c)).c_str());
+}
+
const char *dngn_feature_names[] =
{
"unseen", "closed_door", "secret_door", "wax_wall", "metal_wall",
@@ -1437,6 +1427,25 @@ static int dgn_mons_from_index(lua_State *ls)
return (1);
}
+static int dgn_mons_at(lua_State *ls)
+{
+ COORDS(c, 1, 2);
+
+ monsters *mon = monster_at(c);
+ if (mon && mon->alive())
+ push_monster(ls, mon);
+ else
+ lua_pushnil(ls);
+ return (1);
+}
+
+static int dgn_items_at(lua_State *ls)
+{
+ COORDS(c, 1, 2);
+ lua_push_items(ls, env.igrid(c));
+ return (1);
+}
+
static int lua_dgn_set_lt_callback(lua_State *ls)
{
const char *level_type = luaL_checkstring(ls, 1);
@@ -2054,6 +2063,13 @@ static int dgn_fill_disconnected_zones(lua_State *ls)
return 0;
}
+static int _dgn_is_passable(lua_State *ls)
+{
+ COORDS(c, 1, 2);
+ lua_pushboolean(ls, is_travelsafe_square(c.x, c.y, false, true));
+ return (1);
+}
+
static int dgn_register_feature_marker(lua_State *ls)
{
COORDS(c, 1, 2);
@@ -2075,6 +2091,74 @@ static int dgn_register_lua_marker(lua_State *ls)
return (0);
}
+static int dgn_create_monster(lua_State *ls)
+{
+ COORDS(c, 1, 2);
+
+ if (const char *spec = lua_tostring(ls, 3))
+ {
+ mons_list mlist;
+ const std::string err = mlist.add_mons(spec);
+ if (!err.empty())
+ luaL_error(ls, err.c_str());
+
+ for (int i = 0, size = mlist.size(); i < size; ++i)
+ {
+ mons_spec mspec = mlist.get_monster(i);
+ if (dgn_place_monster(mspec, you.your_level, c,
+ false, false, false))
+ {
+ push_monster(ls, &menv[mgrd(c)]);
+ return (1);
+ }
+ }
+ }
+ lua_pushnil(ls);
+ return (1);
+}
+
+static int dgn_create_item(lua_State *ls)
+{
+ COORDS(c, 1, 2);
+
+ if (const char *spec = lua_tostring(ls, 3))
+ {
+ item_list ilist;
+ const std::string err = ilist.add_item(spec);
+ if (!err.empty())
+ luaL_error(ls, err.c_str());
+
+ const int level =
+ lua_isnumber(ls, 4) ? lua_tointeger(ls, 4) : you.your_level;
+
+ dgn_place_multiple_items(ilist, c, level);
+ link_items();
+ }
+ return (0);
+}
+
+
+#define BRANCH(br, pos) \
+ const char *branch_name = luaL_checkstring(ls, pos); \
+ branch_type req_branch_type = str_to_branch(branch_name); \
+ if (req_branch_type == NUM_BRANCHES) \
+ luaL_error(ls, "Expected branch name"); \
+ Branch &br = branches[req_branch_type]
+
+#define BRANCHFN(name, type, expr) \
+ LUAFN(dgn_br_##name) { \
+ BRANCH(br, 1); \
+ PLUARET(type, expr); \
+ }
+
+BRANCHFN(floorcol, number, br.floor_colour)
+BRANCHFN(rockcol, number, br.rock_colour)
+BRANCHFN(has_shops, boolean, br.has_shops)
+BRANCHFN(has_uniques, boolean, br.has_uniques)
+BRANCHFN(parent_branch, string,
+ br.parent_branch == NUM_BRANCHES ? ""
+ : branches[br.parent_branch].abbrevname)
+
static int dgn_debug_dump_map(lua_State *ls)
{
const int pos = lua_isuserdata(ls, 1) ? 2 : 1;
@@ -2118,6 +2202,7 @@ static const struct luaL_reg dgn_lib[] =
{ "grid", dgn_grid },
{ "max_bounds", dgn_max_bounds },
+ { "colour_at", dgn_colour_at },
{ "terrain_changed", dgn_terrain_changed },
{ "points_connected", dgn_points_connected },
@@ -2138,6 +2223,8 @@ static const struct luaL_reg dgn_lib[] =
{ "feature_desc_at", dgn_feature_desc_at },
{ "item_from_index", dgn_item_from_index },
{ "mons_from_index", dgn_mons_from_index },
+ { "mons_at", dgn_mons_at },
+ { "items_at", dgn_items_at },
{ "change_level_flags", dgn_change_level_flags },
{ "change_branch_flags", dgn_change_branch_flags },
{ "get_floor_colour", dgn_get_floor_colour },
@@ -2169,9 +2256,20 @@ static const struct luaL_reg dgn_lib[] =
{ "join_the_dots", dgn_join_the_dots },
{ "fill_disconnected_zones", dgn_fill_disconnected_zones },
+ { "is_passable", _dgn_is_passable },
+
{ "register_feature_marker", dgn_register_feature_marker },
{ "register_lua_marker", dgn_register_lua_marker },
+ { "create_monster", dgn_create_monster },
+ { "create_item", dgn_create_item },
+
+ { "br_floorcol", dgn_br_floorcol },
+ { "br_rockcol", dgn_br_rockcol },
+ { "br_has_shops", dgn_br_has_shops },
+ { "br_has_uniques", dgn_br_has_uniques },
+ { "br_parent_branch", dgn_br_parent_branch },
+
{ "debug_dump_map", dgn_debug_dump_map },
{ NULL, NULL }
diff --git a/crawl-ref/source/makeitem.cc b/crawl-ref/source/makeitem.cc
index d992d0af7c..bf05dbe144 100644
--- a/crawl-ref/source/makeitem.cc
+++ b/crawl-ref/source/makeitem.cc
@@ -950,7 +950,9 @@ static bool _try_make_weapon_artefact(item_def& item, int force_type,
#ifdef DEBUG_DIAGNOSTICS
mprf(MSGCH_DIAGNOSTICS, "Making fixed artefact.");
#endif
- if (make_item_fixed_artefact( item, (item_level == 51) ))
+ if (make_item_fixed_artefact(
+ item,
+ (item_level == level_id(LEVEL_ABYSS).absdepth()) ))
return (true);
}
diff --git a/crawl-ref/source/mapdef.cc b/crawl-ref/source/mapdef.cc
index 9058fde162..3ff9a014c6 100644
--- a/crawl-ref/source/mapdef.cc
+++ b/crawl-ref/source/mapdef.cc
@@ -1989,6 +1989,7 @@ mons_list::mons_spec_slot mons_list::parse_mons_spec(std::string spec)
mspec.fix_mons = strip_tag(mon_str, "fix_mons");
mspec.generate_awake = strip_tag(mon_str, "generate_awake");
mspec.patrolling = strip_tag(mon_str, "patrolling");
+ mspec.band = strip_tag(mon_str, "band");
// place:Elf:7 to choose monsters appropriate for that level,
// for example.
diff --git a/crawl-ref/source/mapdef.h b/crawl-ref/source/mapdef.h
index 1b9dd721dc..8612eaae04 100644
--- a/crawl-ref/source/mapdef.h
+++ b/crawl-ref/source/mapdef.h
@@ -419,6 +419,7 @@ class mons_spec
bool fix_mons;
bool generate_awake;
bool patrolling;
+ bool band;
int colour;
item_list items;
@@ -430,7 +431,7 @@ class mons_spec
bool _fixmons = false, bool awaken = false, bool patrol = false)
: mid(id), place(), monbase(base), number(num), genweight(gw),
mlevel(ml), fix_mons(_fixmons), generate_awake(awaken),
- patrolling(false), colour(BLACK), items()
+ patrolling(false), band(false), colour(BLACK), items()
{
}
};
diff --git a/crawl-ref/source/mon-pick.cc b/crawl-ref/source/mon-pick.cc
index bb4e392c2e..d608352219 100644
--- a/crawl-ref/source/mon-pick.cc
+++ b/crawl-ref/source/mon-pick.cc
@@ -22,9 +22,9 @@ int mons_level(int mcls, const level_id &place)
int monster_level = 0;
if (place.level_type == LEVEL_ABYSS)
- monster_level = ((mons_abyss(mcls)) ? 51 : 0);
+ monster_level = ((mons_abyss(mcls)) ? place.absdepth() : 0);
else if (place.level_type == LEVEL_PANDEMONIUM)
- monster_level = ((mons_pan(mcls)) ? 52 : 0);
+ monster_level = ((mons_pan(mcls)) ? place.absdepth() : 0);
else if (place.level_type == LEVEL_DUNGEON)
monster_level = branches[place.branch].mons_level_function(mcls);
diff --git a/crawl-ref/source/monplace.cc b/crawl-ref/source/monplace.cc
index 48f43a7b76..49769d06e4 100644
--- a/crawl-ref/source/monplace.cc
+++ b/crawl-ref/source/monplace.cc
@@ -262,6 +262,12 @@ void spawn_random_monsters()
// No monsters in the Labyrinth, or the Ecumenical Temple, or in Bazaars.
}
+monster_type pick_random_monster(const level_id &place)
+{
+ int level = place.absdepth();
+ return pick_random_monster(place, level, level);
+}
+
monster_type pick_random_monster(const level_id &place, int power,
int &lev_mons)
{
@@ -1906,16 +1912,14 @@ int mons_place( mgen_data mg )
// Translate level_type.
switch (mg.level_type)
{
- case LEVEL_PANDEMONIUM:
- mg.power = 52; // sigh..
- break;
- case LEVEL_ABYSS:
- mg.power = 51;
- break;
- case LEVEL_DUNGEON:
- default:
- mg.power = you.your_level;
- break;
+ case LEVEL_PANDEMONIUM:
+ case LEVEL_ABYSS:
+ mg.power = level_id(mg.level_type).absdepth();
+ break;
+ case LEVEL_DUNGEON:
+ default:
+ mg.power = you.your_level;
+ break;
}
int mid = place_monster(mg);
diff --git a/crawl-ref/source/monplace.h b/crawl-ref/source/monplace.h
index 0539686f95..bbb1c80ce4 100644
--- a/crawl-ref/source/monplace.h
+++ b/crawl-ref/source/monplace.h
@@ -254,6 +254,9 @@ int place_monster( mgen_data mg, bool force_pos = false );
* *********************************************************************** */
class level_id;
+
+monster_type pick_random_monster(const level_id &place);
+
monster_type pick_random_monster(const level_id &place,
int power,
int &lev_mons);
diff --git a/crawl-ref/source/traps.cc b/crawl-ref/source/traps.cc
index 796b3f61f7..89f35f7a6c 100644
--- a/crawl-ref/source/traps.cc
+++ b/crawl-ref/source/traps.cc
@@ -1388,22 +1388,7 @@ static int num_traps_default(int level_number, const level_id &place)
int num_traps_for_place(int level_number, const level_id &place)
{
if (level_number == -1)
- {
- switch(place.level_type)
- {
- case LEVEL_DUNGEON:
- level_number = absdungeon_depth(place.branch, place.depth);
- break;
- case LEVEL_ABYSS:
- level_number = 51;
- break;
- case LEVEL_PANDEMONIUM:
- level_number = 52;
- break;
- default:
- level_number = you.your_level;
- }
- }
+ level_number = place.absdepth();
switch (place.level_type)
{
@@ -1473,22 +1458,7 @@ static trap_type random_trap_default(int level_number, const level_id &place)
trap_type random_trap_for_place(int level_number, const level_id &place)
{
if (level_number == -1)
- {
- switch (place.level_type)
- {
- case LEVEL_DUNGEON:
- level_number = absdungeon_depth(place.branch, place.depth);
- break;
- case LEVEL_ABYSS:
- level_number = 51;
- break;
- case LEVEL_PANDEMONIUM:
- level_number = 52;
- break;
- default:
- level_number = you.your_level;
- }
- }
+ level_number = place.absdepth();
switch (place.level_type)
{
diff --git a/crawl-ref/source/travel.cc b/crawl-ref/source/travel.cc
index 9d11cdb4b9..7291a98c78 100644
--- a/crawl-ref/source/travel.cc
+++ b/crawl-ref/source/travel.cc
@@ -3022,7 +3022,18 @@ level_id level_id::current()
int level_id::absdepth() const
{
- return absdungeon_depth(branch, depth);
+ switch (level_type)
+ {
+ case LEVEL_DUNGEON:
+ return absdungeon_depth(branch, depth);
+ case LEVEL_PANDEMONIUM:
+ return 52;
+ case LEVEL_ABYSS:
+ return 51;
+ default:
+ // No true notion of depth here.
+ return you.your_level;
+ }
}
level_id level_id::get_next_level_id(const coord_def &pos)
diff --git a/crawl-ref/source/travel.h b/crawl-ref/source/travel.h
index 9f998ec188..c5a12529dc 100644
--- a/crawl-ref/source/travel.h
+++ b/crawl-ref/source/travel.h
@@ -225,6 +225,8 @@ public:
level_type = LEVEL_DUNGEON;
}
+ int absdepth() const;
+
bool is_valid() const
{
return (branch != NUM_BRANCHES && depth != -1)
@@ -265,8 +267,6 @@ public:
}
- int absdepth() const;
-
void save(writer&) const;
void load(reader&);
};