git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@7553 c06c8d41-db1a-0410-9941-cceddc491573
NKONHW4JNY6HP2M63MNPM3H64ZWSUNUT5FX2STW4KTS4AMXJXXVQC XEESII7USBFCL5OZMNZBVJOI66HRL6BT7CQMAPKZNSLM7YUBBQHQC Q2AYZGR7UBWG4CKVR6PJQD3UHDEBMAFBQ5PZLHT64CTREG3JYFZAC 7FUW7VHYYS2URT45THZ7NJ7NC6JMNGQXJJZ34SPPTBFQHH6RQOJAC KSCU43RIVSEIHTN6BRAKXENI66L3IRDZQHUBT5VS4NJBBCQQPHUQC X7MFMKQTNZ2IWBFVGS6WQV7NRNKJ3DWQAW2X7IQMFQQXW24AHPZQC ZBFNQZV6XCH4NUTHJU4K7RN4KLUMWNCWWO6UP7TIRASCWD5J5OMQC WX2VFNANQZ3IRHBXSLKJT3G3OAQREAZISXLOTG6JO7KXFBHQFOYAC G3UKWY6JNG2ZQO6R2UTAAIQ3ECJIGEKEHTKOJNL5EN4YBC7U44KQC SDLKLUNFGVKDS55DDJZCBAVIB7NL3RRYPTACAY65SCUQKV6APFSAC T6TL6NTIOBYNUIONGK3JFZJ5ONWV6S4CTIRDC5JMKMCBGG5IY3EAC TFZ4TER7O2Z4FOGF2RCPEPYIHBTUA4LG3ECXLR7XGLCC6GO6OOTAC SVY2PTCLXR3KNPQAWXVXTTGCC5DR334HOAKHYO3VDDRWM2BWMALAC L57WEZMVIHTFRLWVIPWOIOWHCF2I53TVUVYJ2V6IZ64R56FVTZZAC UZ6N6HOUPGVSPC5NQROEEDWMEGJA5XUWUY2AKH5QG65AZ25PVXDAC K2CS6TCX2NDVL2ASEHGP4J4K4IJ6FP3ANNKTSIWVG43HPYSBX6ZQC ID373JATLMWAY526Q6Q5FXHRNFWMEOFXPHGPAUUY5OAMPFDN5SJAC GPEJOT73KMACP33IPAKFR5ROGHCOIP22VXZMQNYTGLEA2OSZUM2AC 3UKFCWWS5BLFQWZRB5FUA46CE2XGX5VRCEWC3K3XH5RCGQK64N2AC RPOZZWKG5GLPHVZZ7ZKMKS64ZMV2LDCQSARBJFJ6FZOTOKCQO7FAC 7YSKYUNV34XIWRTJUHJV4QMQRTXXYDIXM5AZSPSDPAYDW4B4PU6QC R2DQBWKIW7YUJB5SOQ7J274JIYRVX4H3ISFRPAL5RG2RVVP4G2KAC APGCKU4AFOV7Z7XIEO5A27H4IFUGDU227I3Z7OIRROYSLOFFBJ5AC Q3DNEB5OOJ34P5ML4CMK3L6SCP7RLW7DDOZEG24KZBX3C7BJRQDAC DTO3EUKWHZ5RJNGNCFYXSOVTIPVXPP637F2W7WFGYKJ7JK7VNKNQC S34LKQDIQJLIWVIPASOJBBZ6ZCXDHP5KPS7TRBZJSCDRVNCLK6UAC ZLQAAP55CJ77XIJN3DZVPT4GTTVLIBFJLIJJKI6L5UBSHX7VUK6AC AUXHSGS4EFOPZ6TVZYWNVOUDO7NYKUKE3HBKGQQWTALSVFOE3HAAC 7Y5HSDFKA5TPLS2TWTRFMQVX6UXUDHXU5MUMXQSDFAIY4THQ3BIQC RGHXFBNIULRVRYLBGG5JZDMYVM2E2JJ2Y5KQPMU6PUS3V26G6ZXQC TLA5UN6LZPXGKERI27EFY4HKIIU3VU5Y7ZU54WXL6ANBUV2VOTMQC LDBTCT5WIPLJPZWXS2RUQ26QKISCUUTLO77M464WOE6VSYSNPKYAC UBQTNLYGD3SNWMUNGWUPX7EXEGQXOXCFCPWIVWBFE7ID7DJLPFWAC IVVTHLTTLOP5TSULXJWUSSXHOKYWVU3OWKYVK45A7RIB6V34MYQAC ED62QWGKBPORWVKDFOQRKJXEIWZVNGR3O4KWQBDSRNPT36AYOQYAC RN242L3YZK35BFY7JRTCSYWD6FWDCRFUFDI7PKYFUCA2UPX6ZEAQC 44YRMW5JNVUBYX3M6UFQOPENNHGO7G2CRZ7SGPIIUTQGYWTRWENAC ASLW3Z5PAVZSWJEMMMVZT226P44EKSAD47QS72JIFJESAI3RPN3AC PRG7UT7G56GT4W3FQ3KG5JRPGMKKJBFDLVHDLYFQK6IZW25JQLBQC G277QSURADDFZIIO5PIMBA4YWHYULQCEGNMNI6TLBWZXHQOOP6FAC 3C2VE43SHCSBY4LTRTFYFLIPRWFUN6DXU6D34QVWDQTSNRBUFG7AC 442VGKMARB6LTQUEBIB5P447EI34BRJL6JALZKXLWPDHWCM6KKCQC B7MSPF6X2RLGWN4M6ZZF3WSOPKGYPTTD7LIJVST7DXN27DG6JHNAC SIDH2P7NBIG5KEOE27XHD3ZT2NQ2OJZFN6VZXWNWYFFY5YVXSSVQC ILN2K6ASDZSMEHOPJ22IZLZJUO6DDGZTKAKXM3YXG6JZZHJNLX4AC 45EMD3KLQPMERNMIKU5G76H6556XOMIW352TSBP7VLWJX2YYGS7AC SQDS2YBPOYDDDCW3GGARBZ2HQIUHCQKL7SSHKFQWDENOL5YNNVNQC EH4VJW3I5Y4V6DT3YMLNDA3NW2DEAV4LRE4T5IEXAVB4WB3JJMGAC JDM27QE4HR52AYFSQE763BFF57ANOTF5MXKMO377PP5EXMN7SAOAC HNXKX6ZDQJV33E7UKZOLBYWJMRZ4QLEMXVXJZNRCTOIG2KVRTIEAC W52PCSHX72WAMWKG6L4BPUBVMO6E72KYYBNKAA7554KNOTY6V7WQC ZJLJGSB2XSBQU42OFQMXL3EG4CXAQGOYAU6YTV2SAWZEJIPFH2CAC UU5EKED2RA2U3CFZ3UEJQEWSWHQPEU7ZD4KH3I22IIVZFHD4Y67QC OYTCBRC7LE44EUVRZVYTOOVKQWJ6P6YE3FXTOGUTNKEMLNWPHKSQC YE7M665QKDGI7Y5WMERCWJNDZ4FUZ6GRUCK4E6GZH4SWCUM6RWLAC E5DMZFW6WCFAKTKKOQPYTQXZ2CGLWMVH64LRXDUI2UIG4VYUHIVQC ZGUJWUFJ4NFFJ6PGXLFGQWCWBCZHPWGWI44NJHJEVPRG5L36PADQC R6XS2HO5QX2FJUGL5UQQRNETKCMYWTUFPHPPS5SYWK3OQA4UDUQQC BPPMLLPJLP6W2LZSPAMOMYA7YWCIFJTNNL3XBWU2MRHAQBZ5M4XAC {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){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();
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;
error = "Can't set floor to black.";}else{error = "No such colour as '";error += s;error += "'";
std::string error;if (colour == forbidden_colour)error = std::string("Can't set floor to ") + s;elseerror = std::string("Unknown colour: '") + s + "'";return luaL_argerror(ls, 1, error.c_str());
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);
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();}
#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); \}
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);}}
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);
-- 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 + 1end
local wall_colours = {"blue", "red", "lightblue", "magenta", "green", "white"}local function wall_colour()return util.random_from(wall_colours)endlocal function random_floor_colour()return wall_colour()
endlocal function map_area()local base_area = 20 + 8 * zig_depth()return 2 * base_area + crawl.random2(base_area)endlocal function clamp_in(val, low, high)if val < low thenreturn lowelseif val > high thenreturn highelsereturn valendendlocal function clamp_in_bounds(x, y)return clamp_in(x, 1, dgn.GXM - 2), clamp_in(y, 1, dgn.GYM - 2)endlocal function rectangle_dimensions()local area = map_area()local cx, cy = dgn.GXM / 2, dgn.GYM / 2local 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, y2endlocal 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 thenzig().level.floor_colour = colourdgn.change_floor_colour(colour)endendlocal function set_random_floor_colour()set_floor_colour( random_floor_colour() )endlocal function mons_random_gen(x, y, nth)set_random_floor_colour()return dgn.create_monster(x, y, "place:" ..util.random_from(mons_populations))endlocal function mons_drac_gen(x, y, nth)set_random_floor_colour()return dgn.create_monster(x, y, "random draconian")endlocal function mons_panlord_gen(x, y, nth)set_random_floor_colour()if nth == 1 thenreturn dgn.create_monster(x, y, "pandemonium lord band")elsereturn dgn.create_monster(x, y, "place:Pan")end
local function monster_creator_fn(arg)if type(arg) == "string" thenlocal _, _, branch = string.find(arg, "^(%w+):")return function (x, y, nth)if branch thenset_floor_colour(dgn.br_floorcol(branch))endreturn dgn.create_monster(x, y, "place:" .. arg)endelsereturn argendendlocal 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 dolocal mons = fn(x, y, nth)if mons thenif mons.experience == 0 thenmons.dismiss()else-- Monster is ok!return monsendendendendendlocal function choose_monster_set()return ziggurat_vet_monster(util.random_from(monster_creators))endlocal 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)endlocal mfn = choose_monster_set()local nth = 1-- No monsterswhile hd_pool > 0 dolocal place = dgn.find_adjacent_point(p, mons_place_p)local mons = mfn(place.x, place.y, nth)if mons thennth = nth + 1hd_pool = hd_pool - mons.hdendendendlocal 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 - cylocal nx2 = cx + y2 - cylocal ny1 = cy + x1 - cxlocal ny2 = cy + x2 - cxreturn { nx1, ny1, nx2, ny2 }endlocal 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) == 0endlocal function free_space_do(fn)local p = dgn.find_adjacent_point(c, is_free_space)if p thenfn(p)endendfor i = 1, nloot doif crawl.one_chance_in(depth) thenfor j = 1, 4 dofree_space_do(function (p)dgn.create_item(p.x, p.y, "*", 20)end)endelsefree_space_do(function (p)dgn.create_item(p.x, p.y, "|", 20)end)endendend
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 thenentry, exit = exit, entryend
crawl.mpr("Ziggurat depth is now " .. zig_depth())
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(), "diagnostic")
-------------------------------------------------------------------------------- util.lua-- Lua utilities.------------------------------------------------------------------------------util = { }function util.catlist(...)local res = { }local tables = { ... }if #tables == 1 thenreturn tables[1]elsefor _, tab in ipairs(tables) dofor _, val in ipairs(tab) dotable.insert(res, val)endendendreturn resendfunction util.cathash(...)local res = { }local tables = { ... }if #tables == 1 thenreturn tables[1]elsefor _, tab in ipairs(tables) dofor key, val in ipairs(tab) dores[key] = valendendendreturn resendfunction util.map(fn, ...)local lists = { ... }local res = { }if #lists == 0 thenreturn reselseif #lists == 1 thenfor _, val in ipairs(lists[1]) dotable.insert(res, fn(val))endelsefor i = 1, #lists[1] dolocal args = { }for _, list in ipairs(lists) doif not list[i] thenbreakendtable.insert(args, list[i])endif #args < #lists thenbreakendtable.insert(res, fn(unpack(args)))endendreturn resendfunction util.random_from(list)return list[ crawl.random2(#list) + 1 ]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) dolocal p = { x = c.x + cp[1], y = c.y + cp[2] }if dgn.in_bounds(p.x, p.y) and faccept(p) thentable.insert(plist, p)endendreturn plistendfunction dgn.find_adjacent_point(c, fcondition, fpassable)local mapped_points = { }local function pstr(p)return p.x .. "," .. p.yendlocal function seen(p)return mapped_points[pstr(p)]endlocal function record(p, val)mapped_points[pstr(p)] = val or 1endif not fpassable thenfpassable = function (p)return dgn.is_passable(p.x, p.y)endendlocal iter_points = { { }, { } }local iter = 1table.insert(iter_points[iter], c)local function next_iter()if iter == 1 thenreturn 2elsereturn 1endendlocal distance = 1record(c, distance)while #iter_points[iter] > 0 dofor _, p in ipairs(iter_points[iter]) doif fcondition(p) thenreturn pend-- Add adjacent points to queue.for _, np in ipairs(dgn.adjacent_points(p, fpassable)) doif not seen(np) thentable.insert(iter_points[next_iter()], np)record(np, distance + 1)endendenditer_points[iter] = { }iter = next_iter()distance = distance + 1end-- No suitable point.return nilendfunction dgn.colour_map(fselect, colour)for x = 0, dgn.GXM - 1 dofor y = 0, dgn.GYM - 1 doif fselect(x, y) thendgn.colour_at(x, y, colour)endendendend
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)
static int l_mons_x(lua_State *ls, monsters *mons, const char *attr)
MDEF(x){PLUARET(number, int(mons->pos().x) - int(you.pos().x));}MDEF(y){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)
lua_pushnumber(ls, int(mons->pos().x) - int(you.pos().x));return (1);
// 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);
{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){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();