diff --git a/dat/Arc-loca.lua b/dat/Arc-loca.lua index 2336a7c6f3..9a335f5542 100644 --- a/dat/Arc-loca.lua +++ b/dat/Arc-loca.lua @@ -33,6 +33,9 @@ local outside = selection.floodfill(00,00) local inside = outside:clone():negate():filter_mapchar('.') des.region(outside, "lit") +-- Ceilings +des.add_ceiling(inside:clone():grow() | selection.area(70,13, 76,19)) + -- Non diggable walls (but leave all trees diggable) local nondig = selection.area(00,00,75,19) ~ selection.area(00,00,50,19):filter_mapchar('T') des.non_diggable(nondig) diff --git a/dat/Arc-strt.lua b/dat/Arc-strt.lua index abc4814c72..633346fad9 100644 --- a/dat/Arc-strt.lua +++ b/dat/Arc-strt.lua @@ -37,6 +37,11 @@ des.map([[ ]]); -- Dungeon Description des.region(selection.area(00,00,76,19), "lit") +-- Ceilings +local exterior = selection.area(00,00, 76,19):filter_mapchar(',') | selection.floodfill(02,06, true) + | selection.area(71,15, 76,19) | selection.area(34,12, 41,14) +local interior = exterior:clone():negate():filter_mapchar('.'):grow() +des.add_ceiling(interior) -- Stairs des.stair("down",76,05) -- Portal arrival point diff --git a/dat/Bar-goal.lua b/dat/Bar-goal.lua index 8c7c58e9d8..7b6ba80c22 100644 --- a/dat/Bar-goal.lua +++ b/dat/Bar-goal.lua @@ -41,6 +41,11 @@ des.teleport_region({ region = {00,00,75,19}, exclude = {06,00,75,19}, dir="down -- and active at the same time. des.teleport_region({ region = {00,00,75,19}, exclude = {41,00,75,19}, dir="up" }) +-- Ceilings +local exterior = selection.floodfill(00,00) + selection.floodfill(57,08) +local covered = exterior:clone():negate():filter_mapchar('.'):grow() +des.add_ceiling(covered) + -- Stair local leftedge = selection.line(00,00, 00,19) des.stair("up", leftedge:rndcoord(1)) diff --git a/dat/Bar-loca.lua b/dat/Bar-loca.lua index 82a855e679..4833a458ac 100644 --- a/dat/Bar-loca.lua +++ b/dat/Bar-loca.lua @@ -37,6 +37,11 @@ des.region(selection.area(35,14,37,15), "unlit") des.region(selection.area(39,03,54,08), "lit") des.region(selection.area(56,00,75,08), "unlit") des.region(selection.area(64,09,75,16), "unlit") +-- Ceilings +local covered = selection.floodfill(00,00, true):negate():filter_mapchar('.') +-- only needed if the caves to the right should actually be uncovered: +-- covered = covered - selection.floodfill(66,05) +des.add_ceiling(covered:grow()) -- Doors des.door("open",23,03) des.door("open",30,08) diff --git a/dat/Bar-strt.lua b/dat/Bar-strt.lua index 5bc69348b2..1b688fdf3e 100644 --- a/dat/Bar-strt.lua +++ b/dat/Bar-strt.lua @@ -55,6 +55,9 @@ des.region(selection.area(26,10,28,11), "lit") des.region(selection.area(04,13,06,14), "lit") des.region(selection.area(15,13,17,14), "lit") des.region(selection.area(22,14,24,15), "lit") +-- Ceilings +local covered = selection.floodfill(00,00):negate():filter_mapchar('.'):grow() +des.add_ceiling(covered) -- Stairs des.stair("down", 09,09) -- Portal arrival point diff --git a/dat/Hea-loca.lua b/dat/Hea-loca.lua index 5f6373944a..44eac910ab 100644 --- a/dat/Hea-loca.lua +++ b/dat/Hea-loca.lua @@ -24,6 +24,8 @@ PPPPPPPPPPP........PPPPPPPPPPPP -- Dungeon Description des.region(selection.area(00,00,30,09), "lit") des.region({ region={12,03, 20,06}, lit=1, type="temple", filled=1 }) +-- Ceilings +des.add_ceiling(selection.area(09,02, 21,07)) -- Doors des.door("closed",09,04) des.door("closed",09,05) diff --git a/dat/Hea-strt.lua b/dat/Hea-strt.lua index 6c25b1841f..02373b73d5 100644 --- a/dat/Hea-strt.lua +++ b/dat/Hea-strt.lua @@ -40,6 +40,8 @@ des.replace_terrain({ region={01,01, 74,18}, fromterrain="P", toterrain=".", cha -- Dungeon Description des.region(selection.area(00,00,75,19), "lit") +-- Ceilings +des.add_ceiling(selection.area(24,07, 50,13)) -- Stairs des.stair("down", 37,9) -- Portal arrival point diff --git a/dat/Kni-strt.lua b/dat/Kni-strt.lua index 59fca9303a..3f31973b6b 100644 --- a/dat/Kni-strt.lua +++ b/dat/Kni-strt.lua @@ -40,6 +40,9 @@ des.region({ region={06,06,22,09}, lit=1, type="throne", filled=2 }) des.region(selection.area(27,06,43,09), "lit") -- Portal arrival point des.levregion({ region = {20,14,20,14}, type="branch" }) +-- Ceilings +local interior = selection.floodfill(00,00):negate():filter_mapchar('.'):grow() +des.add_ceiling(interior) -- Stairs des.stair("down", 40,7) -- Doors diff --git a/dat/Mon-loca.lua b/dat/Mon-loca.lua index 93d24ea94d..8e563d0087 100644 --- a/dat/Mon-loca.lua +++ b/dat/Mon-loca.lua @@ -39,6 +39,10 @@ des.region(selection.area(62,03,72,11), "unlit") des.teleport_region({ region={00,00,06,04}, dir="down" }) des.teleport_region({ region={62,03,72,11}, dir="up" }) +-- Ceilings +local covered = selection.floodfill(67, 4):grow() + selection.floodfill(67, 7) +des.add_ceiling(covered) + -- Stairs des.stair("up", 00,00) des.stair("down", 67,07) diff --git a/dat/Mon-strt.lua b/dat/Mon-strt.lua index 689539bcb5..aab6a0452b 100644 --- a/dat/Mon-strt.lua +++ b/dat/Mon-strt.lua @@ -41,6 +41,11 @@ des.region(selection.area(00,00,75,19), "lit") local spacelocs = selection.floodfill(05,04); +-- Ceilings +local covered = selection.area(55,14, 65,19) | selection.area(54,15, 66,18) + | selection.floodfill(40,09):grow() +des.add_ceiling(covered) + -- Portal arrival point des.levregion({ region = {02,10,02,10}, type="branch" }) diff --git a/dat/Pri-loca.lua b/dat/Pri-loca.lua index 984a04b9a0..99361d6486 100644 --- a/dat/Pri-loca.lua +++ b/dat/Pri-loca.lua @@ -31,6 +31,8 @@ des.region({ region={09,00, 30,01}, lit=0, type="morgue", filled=1 }) des.region({ region={09,12, 30,13}, lit=0, type="morgue", filled=1 }) des.region({ region={31,00, 39,13}, lit=0, type="morgue", filled=1 }) des.region({ region={11,03, 29,10}, lit=1, type="temple", filled=1, irregular=1 }) +-- Ceilings +des.add_ceiling(selection.area(10, 2, 30, 11)) -- The altar inside the temple des.altar({ x=20,y=07, align="noalign", type="shrine" }) des.monster({ id = "aligned cleric", x=20, y=07, align="noalign", peaceful = 0 }) diff --git a/dat/Pri-strt.lua b/dat/Pri-strt.lua index 457949ccbb..68c25b5eec 100644 --- a/dat/Pri-strt.lua +++ b/dat/Pri-strt.lua @@ -47,6 +47,9 @@ local spacelocs = selection.floodfill(05,04); -- Portal arrival point des.levregion({ region = {05,04,05,04}, type="branch" }) +-- Ceilings +local covered = selection.area(20,03, 55,16) | selection.area(18,08, 20,11) +des.add_ceiling(covered) -- Stairs des.stair("down", 52,09) -- Doors diff --git a/dat/Sam-loca.lua b/dat/Sam-loca.lua index 87c08e0cf2..0e5ecc977f 100644 --- a/dat/Sam-loca.lua +++ b/dat/Sam-loca.lua @@ -31,6 +31,12 @@ des.map([[ ]]); -- Dungeon Description des.region(selection.area(00,00,75,19), "lit") +-- Ceiling +local covered = selection.floodfill(00,00, true):negate():filter_mapchar('.') +-- interior courtyard: roofed over out of concern players will waste scrolls of +-- earth not realizing it's a roofless area +-- covered = covered - selection.area(24,07,51,12) +des.add_ceiling(covered:grow()) -- Doors des.door("locked",22,04) des.door("locked",22,15) diff --git a/dat/Sam-strt.lua b/dat/Sam-strt.lua index cfc04083b7..6db56d54bb 100644 --- a/dat/Sam-strt.lua +++ b/dat/Sam-strt.lua @@ -38,6 +38,9 @@ des.map([[ -- Dungeon Description des.region(selection.area(00,00,75,19), "lit") des.region({ region={18,03, 26,07}, lit=1, type="throne", filled=2 }) +-- Ceilings +local covered = selection.area(10,02,60,11) | selection.area(42,12,60,17) +des.add_ceiling(covered) -- Portal arrival zone des.levregion({ region = {62,12,70,17}, type="branch" }) -- Stairs diff --git a/dat/Tou-strt.lua b/dat/Tou-strt.lua index bac7845f80..5aeef544ee 100644 --- a/dat/Tou-strt.lua +++ b/dat/Tou-strt.lua @@ -45,6 +45,10 @@ des.region(selection.area(34,02,39,04), "unlit") des.region(selection.area(41,02,53,04), "unlit") des.region(selection.area(55,02,60,04), "unlit") des.region(selection.area(62,02,67,04), "lit") +-- Ceilings +local covered = selection.area(06,09, 12,13) | selection.area(03,15, 09,19) + | selection.area(16,15, 22,19) | selection.area(24,00, 72,07) +des.add_ceiling(covered) -- Stairs des.stair("down", 66,03) -- Portal arrival point diff --git a/dat/Val-strt.lua b/dat/Val-strt.lua index 13dfccdcb5..76648fb88a 100644 --- a/dat/Val-strt.lua +++ b/dat/Val-strt.lua @@ -42,6 +42,8 @@ local inside = selection.floodfill(34,10) + selection.floodfill(34,06) + selecti local outside = (everything:filter_mapchar('.') + alltheice) - inside local init_monster_area = outside & selection.area(17,00,75,19):grow() des.region(everything, "lit") +-- Ceilings +des.add_ceiling(inside:clone():grow()) -- Lava vents surrounded by water local pools = selection.new() local function growths() diff --git a/dat/Wiz-loca.lua b/dat/Wiz-loca.lua index 33460d92a1..acb3fd51ce 100644 --- a/dat/Wiz-loca.lua +++ b/dat/Wiz-loca.lua @@ -72,6 +72,8 @@ des.region({ region={48,10,54,10}, lit=0, type="ordinary", irregular=1, end }) +-- Ceilings +des.add_ceiling(selection.area(36,03, 66,17)) -- Doors des.door("locked",55,08) des.door("locked",55,12) diff --git a/dat/Wiz-strt.lua b/dat/Wiz-strt.lua index 285530774a..f49e3ba4ad 100644 --- a/dat/Wiz-strt.lua +++ b/dat/Wiz-strt.lua @@ -35,7 +35,11 @@ des.map([[ ......................CCC.C................................................. ]]); --- first do cloud everywhere +-- Add ceilings before anything else, so floodfill will work +local covered = selection.floodfill(00,00):negate():filter_mapchar('.'):grow() + | selection.area(11,08, 35,12) +des.add_ceiling(covered) +-- do cloud everywhere des.replace_terrain({ region={0,0, 75,19}, fromterrain=".", toterrain="C", chance=10 }) -- then replace clouds inside the tower back to floor des.replace_terrain({ region={13,5, 33,15}, fromterrain="C", toterrain=".", chance=100 }) diff --git a/include/extern.h b/include/extern.h index ce90664bae..dc22cf76e4 100644 --- a/include/extern.h +++ b/include/extern.h @@ -742,6 +742,7 @@ extern boolean Is_botlevel(d_level *); extern boolean Can_fall_thru(d_level *); extern boolean Can_dig_down(d_level *); extern boolean Can_rise_up(coordxy, coordxy, d_level *); +extern boolean ceiling_exists(coordxy, coordxy); extern boolean has_ceiling(d_level *); extern boolean avoid_ceiling(d_level *); extern const char *surface(coordxy, coordxy); diff --git a/include/flag.h b/include/flag.h index 63c232eb7d..fb730c9292 100644 --- a/include/flag.h +++ b/include/flag.h @@ -331,6 +331,7 @@ struct instance_flags { boolean fireassist; /* autowield launcher when using fire-command */ boolean time_botl; /* context.botl for 'time' (moves) only */ boolean wizmgender; /* test gender info from core in window port */ + boolean wizceiling; /* highlight ceilngs */ boolean invweight; /* display weights of items in inventory */ boolean msg_is_alert; /* suggest windowport should grab player's attention * and request acknowlegement */ diff --git a/include/optlist.h b/include/optlist.h index daa5fc8333..7d0726f9a3 100644 --- a/include/optlist.h +++ b/include/optlist.h @@ -823,6 +823,9 @@ static int optfn_##a(int, int, boolean, char *, char *); No, Yes, No, No, NoAlias, "the foreground/background colors of windows") /* NHOPTC(windowtype) -- moved to top */ + NHOPTB(wizceiling, Advanced, 0, opt_in, set_wizonly, + Off, Yes, No, No, NoAlias, &iflags.wizceiling, Term_False, + (char *) 0) NHOPTB(wizmgender, Advanced, 0, opt_in, set_wizonly, Off, Yes, No, No, NoAlias, &iflags.wizmgender, Term_False, (char *)0) diff --git a/include/rm.h b/include/rm.h index 50a6f95914..af636a95ed 100644 --- a/include/rm.h +++ b/include/rm.h @@ -251,7 +251,8 @@ struct rm { Bitfield(candig, 1); /* Exception to Can_dig_down; was a trapdoor */ Bitfield(uvisited, 1); /* player has visited this space */ - Bitfield(unused, 6); /* currently unused - take bits out of this rather + Bitfield(ceiling, 1); /* special ceiling status */ + Bitfield(unused, 5); /* currently unused - take bits out of this rather than overloading it as if it were a second flags field! */ }; diff --git a/include/trap.h b/include/trap.h index 68346b8008..cca9639f85 100644 --- a/include/trap.h +++ b/include/trap.h @@ -121,6 +121,7 @@ enum { Trap_Effect_Finished = 0, || (ttyp) == MAGIC_TRAP \ || (ttyp) == ANTI_MAGIC \ || (ttyp) == POLY_TRAP) +#define is_ceiling_trap(ttyp) ((ttyp) == ROCKTRAP || (ttyp) == RUST_TRAP) /* "transportation" traps */ #define is_xport(ttyp) ((ttyp) >= TELEP_TRAP && (ttyp) <= MAGIC_PORTAL) diff --git a/src/dig.c b/src/dig.c index 7cfe54ad86..ebdd3a7264 100644 --- a/src/dig.c +++ b/src/dig.c @@ -1497,7 +1497,7 @@ zap_dig(void) if (u.dz) { if (!Is_airlevel(&u.uz) && !Is_waterlevel(&u.uz) && !Underwater) { if ((u.dz < 0 || On_stairs(u.ux, u.uy)) - && !gl.level.flags.outdoors) { + && ceiling_exists(u.ux, u.uy)) { int dmg; if (On_stairs(u.ux, u.uy)) { stairway *stway = stairway_at(u.ux, u.uy); diff --git a/src/display.c b/src/display.c index 12551469bf..2dc1a1c39f 100644 --- a/src/display.c +++ b/src/display.c @@ -2613,6 +2613,11 @@ map_glyphinfo( ? CLR_GRAY : CLR_WHITE; } } + if (iflags.wizceiling && wizard && isok(x, y) && levl[x][y].ceiling) { + glyphinfo->gm.sym.color = CLR_RED; + /* glyphinfo->gm.sym.symidx */ + glyphinfo->gm.glyphflags |= MG_OBJPILE; + } #endif /* TEXTCOLOR */ glyphinfo->ttychar = gs.showsyms[glyphinfo->gm.sym.symidx]; glyphinfo->glyph = glyph; diff --git a/src/dothrow.c b/src/dothrow.c index ce9734e0de..ec372beee6 100644 --- a/src/dothrow.c +++ b/src/dothrow.c @@ -1309,7 +1309,7 @@ toss_up(struct obj *obj, boolean hitsroof) && touch_petrifies(&mons[obj->corpsenm])); /* note: obj->quan == 1 */ - if (!has_ceiling(&u.uz)) { + if (!ceiling_exists(u.ux, u.uy)) { action = "flies up into"; /* into "the sky" or "the water above" */ } else if (hitsroof) { if (breaktest(obj)) { diff --git a/src/dungeon.c b/src/dungeon.c index 22ca20ee84..79f9a79ce0 100644 --- a/src/dungeon.c +++ b/src/dungeon.c @@ -1803,7 +1803,7 @@ ceiling(coordxy x, coordxy y) else if (Is_waterlevel(&u.uz)) /* water plane has no surface; its air bubbles aren't below sky */ what = "water above"; - else if (!has_ceiling(&u.uz)) + else if (!ceiling_exists(x, y)) what = "sky"; else if (Is_firelevel(&u.uz)) what = "flames above"; @@ -1864,6 +1864,26 @@ surface(coordxy x, coordxy y) return "ground"; } +boolean +ceiling_exists(coordxy x, coordxy y) +{ + /* no exceptions on certain levels */ + if (Is_airlevel(&u.uz) || Is_waterlevel(&u.uz)) + return FALSE; + if (!gl.level.flags.outdoors) + return TRUE; + /* if we're given 0,0 or similar out-of-bounds candidate, just return + the default ceiling state for the level -- after previous checks it + must be no-ceiling */ + if (!isok(x, y)) + return FALSE; + /* now check for exceptions */ + if (levl[x][y].ceiling) + return TRUE; + + return FALSE; +} + /* * It is expected that the second argument of get_level is a depth value, * either supplied by the user (teleport control) or randomly generated. diff --git a/src/mklev.c b/src/mklev.c index d80263b6fc..3cf71e17ed 100644 --- a/src/mklev.c +++ b/src/mklev.c @@ -1965,7 +1965,7 @@ mktrap( case RUST_TRAP: case ROCKTRAP: /* certain traps that rely on a ceiling to make sense */ - if (!has_ceiling(&u.uz)) + if (tm && !ceiling_exists(tm->x, tm->y)) kind = NO_TRAP; } } while (kind == NO_TRAP); @@ -1978,7 +1978,8 @@ mktrap( m = *tm; } else { register int tryct = 0; - boolean avoid_boulder = (is_pit(kind) || is_hole(kind)); + boolean avoid_boulder = (is_pit(kind) || is_hole(kind)), + need_ceiling = is_ceiling_trap(kind); /* Try up to 200 times to find a random coordinate for the trap. */ do { @@ -1989,7 +1990,8 @@ mktrap( else if (!somexyspace(croom, &m)) return; } while (occupied(m.x, m.y) - || (avoid_boulder && sobj_at(BOULDER, m.x, m.y))); + || (avoid_boulder && sobj_at(BOULDER, m.x, m.y)) + || (need_ceiling && !ceiling_exists(m.x, m.y))); } t = maketrap(m.x, m.y, kind); diff --git a/src/mon.c b/src/mon.c index a1f4c73e21..39e22b9835 100644 --- a/src/mon.c +++ b/src/mon.c @@ -159,14 +159,14 @@ sanity_check_single_mon( if (ceiling_hider(mptr) /* normally !accessible would be overridable with passes_walls, but not for hiding on the ceiling */ - && (!has_ceiling(&u.uz) || - !(levl[mx][my].typ == POOL - || levl[mx][my].typ == MOAT - || levl[mx][my].typ == LAVAPOOL - || accessible(mx, my)))) + && (!ceiling_exists(mx, my) + || !(levl[mx][my].typ == POOL + || levl[mx][my].typ == MOAT + || levl[mx][my].typ == LAVAPOOL + || accessible(mx, my)))) impossible("ceiling hider hiding %s (%s)", - !has_ceiling(&u.uz) ? "without ceiling" - : "in solid stone", + !ceiling_exists(mx, my) ? "without ceiling" + : "in solid stone", msg); if (mtmp->mtrapped && (t = t_at(mx, my)) != 0 && !is_pit(t->ttyp)) impossible("hiding while trapped in a non-pit (%s)", msg); @@ -4634,7 +4634,7 @@ restrap(struct monst *mtmp) set_mimic_sym(mtmp); return TRUE; } else if (levl[mtmp->mx][mtmp->my].typ == ROOM - && has_ceiling(&u.uz)) { + && ceiling_exists(mtmp->mx, mtmp->my)) { mtmp->mundetected = 1; return TRUE; } diff --git a/src/muse.c b/src/muse.c index 2fdb3bb4b2..e687885f2b 100644 --- a/src/muse.c +++ b/src/muse.c @@ -1443,6 +1443,7 @@ find_offensive(struct monst *mtmp) || !rn2(10)) && dist2(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy) <= 2 && mtmp->mcansee && haseyes(mtmp->data) + && ceiling_exists(mtmp->mx, mtmp->my) && (!In_endgame(&u.uz) || Is_earthlevel(&u.uz))) { gm.m.offensive = obj; gm.m.has_offense = MUSE_SCR_EARTH; @@ -1783,6 +1784,7 @@ use_offensive(struct monst *mtmp) for (y = mmy - 1; y <= mmy + 1; y++) { /* Is this a suitable spot? */ if (isok(x, y) && !closed_door(x, y) + && ceiling_exists(x, y) && !IS_ROCK(levl[x][y].typ) && !IS_AIR(levl[x][y].typ) && (((x == mmx) && (y == mmy)) ? !is_blessed : !is_cursed) && (x != u.ux || y != u.uy)) { @@ -1791,7 +1793,8 @@ use_offensive(struct monst *mtmp) } } /* Attack the player */ - if (distmin(mmx, mmy, u.ux, u.uy) == 1 && !is_cursed) { + if (distmin(mmx, mmy, u.ux, u.uy) == 1 && !is_cursed + && ceiling_exists(u.ux, u.uy)) { drop_boulder_on_player(confused, !is_cursed, FALSE, TRUE); } diff --git a/src/options.c b/src/options.c index 2b66e325b4..fa562bb8f9 100644 --- a/src/options.c +++ b/src/options.c @@ -5004,6 +5004,7 @@ optfn_boolean(int optidx, int req, boolean negated, char *opts, char *op) if (iflags.use_color) go.opt_need_redraw = TRUE; /* darkroom refresh */ break; + case opt_wizceiling: case opt_wizmgender: case opt_showrace: case opt_use_inverse: diff --git a/src/polyself.c b/src/polyself.c index d232b2bd57..1cfdd57e91 100644 --- a/src/polyself.c +++ b/src/polyself.c @@ -1851,7 +1851,7 @@ dohide(void) } } /* Planes of Air and Water */ - if (on_ceiling && !has_ceiling(&u.uz)) { + if (on_ceiling && !ceiling_exists(u.ux, u.uy)) { There("is nowhere to hide above you."); u.uundetected = 0; return ECMD_OK; diff --git a/src/potion.c b/src/potion.c index bd0697188e..a0ad52335a 100644 --- a/src/potion.c +++ b/src/potion.c @@ -1400,7 +1400,7 @@ peffect_levitation(struct obj *otmp) /* in case we're already Levitating, which would have resulted in incrementing 'nothing' */ gp.potion_nothing = 0; /* not nothing after all */ - } else if (has_ceiling(&u.uz)) { + } else if (ceiling_exists(u.ux, u.uy)) { int dmg = rnd(!uarmh ? 10 : !is_hard(uarmh) ? 6 : 3); You("hit your %s on the %s.", body_part(HEAD), diff --git a/src/read.c b/src/read.c index b722c90e69..e7a4ca2224 100644 --- a/src/read.c +++ b/src/read.c @@ -1984,7 +1984,7 @@ seffect_earth(struct obj **sobjp) } pline("The earth moves around you!"); } - else if (has_ceiling(&u.uz) + else if (ceiling_exists(u.ux, u.uy) && (!In_endgame(&u.uz) || Is_earthlevel(&u.uz))) { coordxy x, y; int nboulders = 0; @@ -2016,6 +2016,7 @@ seffect_earth(struct obj **sobjp) for (y = u.uy - 1; y <= u.uy + 1; y++) { /* Is this a suitable spot? */ if (isok(x, y) && !closed_door(x, y) + && ceiling_exists(x, y) && !IS_ROCK(levl[x][y].typ) && !IS_AIR(levl[x][y].typ) && (x != u.ux || y != u.uy)) { @@ -2025,7 +2026,7 @@ seffect_earth(struct obj **sobjp) } } /* Attack the player */ - if (!sblessed) { + if (!sblessed && ceiling_exists(u.ux, u.uy)) { drop_boulder_on_player(FALSE, !scursed, TRUE, FALSE); } else if (!nboulders) pline("But nothing else happens."); diff --git a/src/sp_lev.c b/src/sp_lev.c index 9a15c99c47..af2bdb4b02 100644 --- a/src/sp_lev.c +++ b/src/sp_lev.c @@ -102,6 +102,8 @@ static void get_table_xy_or_coord(lua_State *, lua_Integer *, lua_Integer *); static int get_table_region(lua_State *, const char *, lua_Integer *, lua_Integer *, lua_Integer *, lua_Integer *, boolean); static void set_wallprop_in_selection(lua_State *, int); +static void set_prop_in_selection(lua_State *, select_iter_func, int); +static void sel_set_ceiling(coordxy, coordxy, genericptr_t); static coordxy random_wdir(void); static int floodfillchk_match_under(coordxy, coordxy); static int floodfillchk_match_accessible(coordxy, coordxy); @@ -144,6 +146,7 @@ int lspo_mineralize(lua_State *); int lspo_monster(lua_State *); int lspo_non_diggable(lua_State *); int lspo_non_passwall(lua_State *); +int lspo_add_ceiling(lua_State *); int lspo_object(lua_State *); int lspo_portal(lua_State *); int lspo_random_corridors(lua_State *); @@ -6668,6 +6671,12 @@ lspo_wall_property(lua_State *L) static void set_wallprop_in_selection(lua_State *L, int prop) +{ + set_prop_in_selection(L, sel_set_wall_property, prop); +} + +static void +set_prop_in_selection(lua_State *L, select_iter_func set, int prop) { int argc = lua_gettop(L); boolean freesel = FALSE; @@ -6684,7 +6693,7 @@ set_wallprop_in_selection(lua_State *L, int prop) } if (sel) { - selection_iterate(sel, sel_set_wall_property, (genericptr_t) &prop); + selection_iterate(sel, set, (genericptr_t) &prop); if (freesel) selection_free(sel, TRUE); } @@ -6708,6 +6717,25 @@ lspo_non_passwall(lua_State *L) return 0; } +static void +sel_set_ceiling(coordxy x, coordxy y, genericptr_t arg) +{ + int val = *(int *)arg; + + levl[x][y].ceiling = val; +} + +/* should be used for 'outdoors' flagged levels, to specify areas which have + * ceilings */ +/* add_ceiling(selection); */ +/* add_ceiling(); */ +int +lspo_add_ceiling(lua_State *L) +{ + set_prop_in_selection(L, sel_set_ceiling, 1); + return 0; +} + #if 0 /*ARGSUSED*/ static void @@ -7173,6 +7201,7 @@ static const struct luaL_Reg nhl_functions[] = { { "wall_property", lspo_wall_property }, { "non_diggable", lspo_non_diggable }, { "non_passwall", lspo_non_passwall }, + { "add_ceiling", lspo_add_ceiling }, { "teleport_region", lspo_teleport_region }, { "reset_level", lspo_reset_level }, { "finalize_level", lspo_finalize_level }, diff --git a/src/zap.c b/src/zap.c index 881a7c15e1..b0303ab53b 100644 --- a/src/zap.c +++ b/src/zap.c @@ -3225,9 +3225,8 @@ zap_updown(struct obj *obj) /* wand or spell */ else destroy_drawbridge(xx, yy); disclose = TRUE; - } else if (striking && u.dz < 0 && rn2(3) && !Is_airlevel(&u.uz) - && !Is_waterlevel(&u.uz) && !Underwater - && !Is_qstart(&u.uz)) { + } else if (striking && u.dz < 0 && rn2(3) + && ceiling_exists(x, y) && !Underwater) { int dmg; /* similar to zap_dig() */ pline("A rock is dislodged from the %s and falls on your %s.",