Skip to content
3 changes: 3 additions & 0 deletions dat/Arc-loca.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
5 changes: 5 additions & 0 deletions dat/Arc-strt.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
5 changes: 5 additions & 0 deletions dat/Bar-goal.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
5 changes: 5 additions & 0 deletions dat/Bar-loca.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
3 changes: 3 additions & 0 deletions dat/Bar-strt.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions dat/Hea-loca.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 2 additions & 0 deletions dat/Hea-strt.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 3 additions & 0 deletions dat/Kni-strt.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 4 additions & 0 deletions dat/Mon-loca.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
5 changes: 5 additions & 0 deletions dat/Mon-strt.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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" })

Expand Down
2 changes: 2 additions & 0 deletions dat/Pri-loca.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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 })
Expand Down
3 changes: 3 additions & 0 deletions dat/Pri-strt.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 6 additions & 0 deletions dat/Sam-loca.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
3 changes: 3 additions & 0 deletions dat/Sam-strt.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 4 additions & 0 deletions dat/Tou-strt.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions dat/Val-strt.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
2 changes: 2 additions & 0 deletions dat/Wiz-loca.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
6 changes: 5 additions & 1 deletion dat/Wiz-strt.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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 })
Expand Down
1 change: 1 addition & 0 deletions include/extern.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
1 change: 1 addition & 0 deletions include/flag.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 <TAB> acknowlegement */
Expand Down
3 changes: 3 additions & 0 deletions include/optlist.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
3 changes: 2 additions & 1 deletion include/rm.h
Original file line number Diff line number Diff line change
Expand Up @@ -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! */
};
Expand Down
1 change: 1 addition & 0 deletions include/trap.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
2 changes: 1 addition & 1 deletion src/dig.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
5 changes: 5 additions & 0 deletions src/display.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion src/dothrow.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)) {
Expand Down
22 changes: 21 additions & 1 deletion src/dungeon.c
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down Expand Up @@ -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.
Expand Down
8 changes: 5 additions & 3 deletions src/mklev.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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 {
Expand All @@ -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);
Expand Down
16 changes: 8 additions & 8 deletions src/mon.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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;
}
Expand Down
5 changes: 4 additions & 1 deletion src/muse.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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)) {
Expand All @@ -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);
}

Expand Down
1 change: 1 addition & 0 deletions src/options.c
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
Loading