Shaped and themed rooms

Allows creating shaped or themed rooms for the Dungeons of Doom
via lua script.

Invalidates bones and saves.

Makefiles updated for unix/linux by adding themerms.lua, but other
OSes need to have that added.
This commit is contained in:
Pasi Kallinen
2020-04-09 07:22:22 +03:00
parent 2d43c6d62a
commit 9b74ea0b22
16 changed files with 842 additions and 53 deletions

View File

@@ -9,6 +9,9 @@
/* croom->lx etc are schar (width <= int), so % arith ensures that */
/* conversion of result to int is reasonable */
static boolean FDECL(generate_stairs_room_good, (struct mkroom *, int));
static struct mkroom *NDECL(generate_stairs_find_room);
static void NDECL(generate_stairs);
static void FDECL(mkfount, (int, struct mkroom *));
static boolean FDECL(find_okay_roompos, (struct mkroom *, coord *));
static void FDECL(mksink, (struct mkroom *));
@@ -94,9 +97,14 @@ xchar xl, yl, xh, yh;
return;
}
/* Sort rooms on the level so they're ordered from left to right on the map.
makecorridors() by default links rooms N and N+1 */
void
sort_rooms()
{
int i, x, y;
int ri[MAXNROFROOMS+1];
#if defined(SYSV) || defined(DGUX)
#define CAST_nroom (unsigned) g.nroom
#else
@@ -104,6 +112,17 @@ sort_rooms()
#endif
qsort((genericptr_t) g.rooms, CAST_nroom, sizeof (struct mkroom), do_comp);
#undef CAST_nroom
/* Update the roomnos on the map */
for (i = 0; i < g.nroom; i++)
ri[g.rooms[i].roomnoidx] = i;
for (x = 1; x < COLNO; x++)
for (y = 0; y < ROWNO; y++) {
int rno = levl[x][y].roomno;
if (rno >= ROOMOFFSET && rno < MAXNROFROOMS+1)
levl[x][y].roomno = ri[rno - ROOMOFFSET] + ROOMOFFSET;
}
}
static void
@@ -140,6 +159,7 @@ boolean is_room;
} else
croom->rlit = 0;
croom->roomnoidx = (croom - g.rooms);
croom->lx = lowx;
croom->hx = hix;
croom->ly = lowy;
@@ -156,6 +176,7 @@ boolean is_room;
croom->nsubrooms = 0;
croom->sbrooms[0] = (struct mkroom *) 0;
if (!special) {
croom->needjoining = TRUE;
for (x = lowx - 1; x <= hix + 1; x++)
for (y = lowy - 1; y <= hiy + 1; y += (hiy - lowy + 2)) {
levl[x][y].typ = HWALL;
@@ -222,6 +243,27 @@ static void
makerooms()
{
boolean tried_vault = FALSE;
int themeroom_tries = 0;
boolean dothemes = (g.dungeons[u.uz.dnum].themelua != NULL);
char *fname = g.dungeons[u.uz.dnum].themerms;
if (*fname && !g.dungeons[u.uz.dnum].themelua) {
g.dungeons[u.uz.dnum].themelua = nhl_init();
if (g.dungeons[u.uz.dnum].themelua) {
if (!nhl_loadlua(g.dungeons[u.uz.dnum].themelua, fname)) {
/* loading lua failed, don't use themed rooms */
g.dungeons[u.uz.dnum].themerms[0] = '\0';
lua_close(g.dungeons[u.uz.dnum].themelua);
g.dungeons[u.uz.dnum].themelua = NULL;
} else {
dothemes = TRUE;
}
}
}
if (dothemes) {
create_des_coder();
}
/* make rooms until satisfied */
/* rnd_rect() will returns 0 if no more rects are available... */
@@ -233,10 +275,26 @@ makerooms()
g.vault_y = g.rooms[g.nroom].ly;
g.rooms[g.nroom].hx = -1;
}
} else if (!create_room(-1, -1, -1, -1, -1, -1, OROOM, -1))
return;
} else {
if (dothemes) {
g.in_mk_themerooms = TRUE;
g.themeroom_failed = FALSE;
lua_getglobal(g.dungeons[u.uz.dnum].themelua, "themerooms_generate");
lua_call(g.dungeons[u.uz.dnum].themelua, 0, 0);
g.in_mk_themerooms = FALSE;
if (g.themeroom_failed && ((themeroom_tries++ > 10) || (g.nroom >= (MAXNROFROOMS / 6))))
break;
} else {
if (!create_room(-1, -1, -1, -1, -1, -1, OROOM, -1))
break;;
}
}
}
if (dothemes) {
wallification(1, 0, COLNO - 1, ROWNO - 1);
free(g.coder);
g.coder = NULL;
}
return;
}
static void
@@ -252,6 +310,9 @@ boolean nxcor;
croom = &g.rooms[a];
troom = &g.rooms[b];
if (!croom->needjoining || !troom->needjoining)
return;
/* find positions cc and tt for doors in croom and troom
and direction for a corridor between them */
@@ -711,25 +772,7 @@ makelevel()
makerooms();
sort_rooms();
/* construct stairs (up and down in different rooms if possible) */
croom = &g.rooms[rn2(g.nroom)];
if (!Is_botlevel(&u.uz))
mkstairs(somex(croom), somey(croom), 0, croom); /* down */
if (g.nroom > 1) {
troom = croom;
croom = &g.rooms[rn2(g.nroom - 1)];
if (croom == troom)
croom++;
}
if (u.uz.dlevel != 1) {
xchar sx, sy;
do {
sx = somex(croom);
sy = somey(croom);
} while (occupied(sx, sy));
mkstairs(sx, sy, 1, croom); /* up */
}
generate_stairs(); /* up and down stairs */
branchp = Is_branchlev(&u.uz); /* possible dungeon branch */
room_threshold = branchp ? 4 : 3; /* minimum number of rooms needed
@@ -807,7 +850,10 @@ makelevel()
/* for each room: put things inside */
for (croom = g.rooms; croom->hx > 0; croom++) {
int trycnt = 0;
if (croom->rtype != OROOM)
coord pos;
if (croom->rtype != OROOM && croom->rtype != THEMEROOM)
continue;
if (!croom->needfill)
continue;
/* put a sleeping monster inside */
@@ -816,13 +862,11 @@ makelevel()
while a monster was on the stairs. Conclusion:
we have to check for monsters on the stairs anyway. */
if (u.uhave.amulet || !rn2(3)) {
x = somex(croom);
y = somey(croom);
tmonst = makemon((struct permonst *) 0, x, y, MM_NOGRP);
if ((u.uhave.amulet || !rn2(3)) && somexyspace(croom, &pos)) {
tmonst = makemon((struct permonst *) 0, pos.x, pos.y, MM_NOGRP);
if (tmonst && tmonst->data == &mons[PM_GIANT_SPIDER]
&& !occupied(x, y))
(void) maketrap(x, y, WEB);
&& !occupied(pos.x, pos.y))
(void) maketrap(pos.x, pos.y, WEB);
}
/* put traps and mimics inside */
x = 8 - (level_difficulty() / 6);
@@ -830,8 +874,8 @@ makelevel()
x = 2;
while (!rn2(x) && (++trycnt < 1000))
mktrap(0, 0, croom, (coord *) 0);
if (!rn2(3))
(void) mkgold(0L, somex(croom), somey(croom));
if (!rn2(3) && somexyspace(croom, &pos))
(void) mkgold(0L, pos.x, pos.y);
if (Is_rogue_level(&u.uz))
goto skip_nonrogue;
if (!rn2(10))
@@ -847,18 +891,18 @@ makelevel()
mkgrave(croom);
/* put statues inside */
if (!rn2(20))
if (!rn2(20) && somexyspace(croom, &pos))
(void) mkcorpstat(STATUE, (struct monst *) 0,
(struct permonst *) 0, somex(croom),
somey(croom), CORPSTAT_INIT);
(struct permonst *) 0, pos.x,
pos.y, CORPSTAT_INIT);
/* put box/chest inside;
* 40% chance for at least 1 box, regardless of number
* of rooms; about 5 - 7.5% for 2 boxes, least likely
* when few rooms; chance for 3 or more is negligible.
*/
if (!rn2(g.nroom * 5 / 2))
(void) mksobj_at((rn2(3)) ? LARGE_BOX : CHEST, somex(croom),
somey(croom), TRUE, FALSE);
if (!rn2(g.nroom * 5 / 2) && somexyspace(croom, &pos))
(void) mksobj_at((rn2(3)) ? LARGE_BOX : CHEST,
pos.x, pos.y, TRUE, FALSE);
/* maybe make some graffiti */
if (!rn2(27 + 3 * abs(depth(&u.uz)))) {
@@ -867,8 +911,9 @@ makelevel()
if (mesg) {
do {
x = somex(croom);
y = somey(croom);
somexyspace(croom, &pos);
x = pos.x;
y = pos.y;
} while (levl[x][y].typ != ROOM && !rn2(40));
if (!(IS_POOL(levl[x][y].typ)
|| IS_FURNITURE(levl[x][y].typ)))
@@ -877,15 +922,15 @@ makelevel()
}
skip_nonrogue:
if (!rn2(3)) {
(void) mkobj_at(0, somex(croom), somey(croom), TRUE);
if (!rn2(3) && somexyspace(croom, &pos)) {
(void) mkobj_at(0, pos.x, pos.y, TRUE);
tryct = 0;
while (!rn2(5)) {
if (++tryct > 100) {
impossible("tryct overflow4");
break;
}
(void) mkobj_at(0, somex(croom), somey(croom), TRUE);
(void) mkobj_at(0, pos.x, pos.y, TRUE);
}
}
}
@@ -1124,7 +1169,7 @@ coord *mp;
do
croom = &g.rooms[rn2(g.nroom)];
while ((croom == g.dnstairs_room || croom == g.upstairs_room
|| croom->rtype != OROOM) && (++tryct < 100));
|| (croom->rtype != OROOM && croom->rtype != THEMEROOM)) && (++tryct < 100));
} else
croom = &g.rooms[rn2(g.nroom)];
@@ -1133,6 +1178,7 @@ coord *mp;
impossible("Can't place branch!");
} while ((occupied(mp->x, mp->y)
|| (levl[mp->x][mp->y].typ != CORR
&& levl[mp->x][mp->y].typ != ICE
&& levl[mp->x][mp->y].typ != ROOM)) && (++cnt < 1000));
}
return croom;
@@ -1250,6 +1296,10 @@ xchar x, y;
boolean near_door = bydoor(x, y);
return ((levl[x][y].typ == HWALL || levl[x][y].typ == VWALL)
&& (isok(x-1,y) && !IS_ROCK(levl[x-1][y].typ)
|| isok(x+1,y) && !IS_ROCK(levl[x+1][y].typ)
|| isok(x,y-1) && !IS_ROCK(levl[x][y-1].typ)
|| isok(x,y+1) && !IS_ROCK(levl[x][y+1].typ))
&& g.doorindex < DOORMAX && !near_door);
}
@@ -1574,6 +1624,83 @@ struct mkroom *croom;
levl[x][y].ladder = up ? LA_UP : LA_DOWN;
}
/* is room a good one to generate up or down stairs in? */
/* phase values, smaller allows for more relaxed criteria:
2 == no relaxed criteria
1 == allow a themed room
0 == allow same room as existing up/downstairs
-1 == allow an unjoined room
*/
static boolean
generate_stairs_room_good(croom, phase)
struct mkroom *croom;
int phase;
{
return (croom && (croom->needjoining || (phase < 0))
&& ((croom != g.dnstairs_room && croom != g.upstairs_room)
|| phase < 1)
&& (croom->rtype == OROOM
|| ((phase < 2) || croom->rtype == THEMEROOM)));
}
/* find a good room to generate an up or down stairs in */
static struct mkroom *
generate_stairs_find_room()
{
struct mkroom *croom;
int i, phase, tryct = 0;
if (!g.nroom)
return (struct mkroom *) 0;
for (phase = 2; phase > -1; phase--) {
do {
croom = &g.rooms[rn2(g.nroom)];
} while (!generate_stairs_room_good(croom, phase) && (tryct++ < 50));
if (tryct < 50)
return croom;
}
for (phase = 2; phase > -2; phase--) {
for (i = 0; i < g.nroom; i++) {
croom = &g.rooms[i];
if (generate_stairs_room_good(croom, phase))
return croom;
}
}
croom = &g.rooms[rn2(g.nroom)];
return croom;
}
/* construct stairs up and down within the same branch,
up and down in different rooms if possible */
static void
generate_stairs()
{
struct mkroom *croom = generate_stairs_find_room();
coord pos;
if (!Is_botlevel(&u.uz)) {
if (!somexyspace(croom, &pos)) {
pos.x = somex(croom);
pos.y = somey(croom);
}
mkstairs(pos.x, pos.y, 0, croom); /* down */
}
if (g.nroom > 1)
croom = generate_stairs_find_room();
if (u.uz.dlevel != 1) {
if (!somexyspace(croom, &pos)) {
pos.x = somex(croom);
pos.y = somey(croom);
}
mkstairs(pos.x, pos.y, 1, croom); /* up */
}
}
static void
mkfount(mazeflag, croom)
int mazeflag;