Add a new themed room: "Twin business"

This themed room boasts two shops, a weapons and an armor store,
that can generate in a number of different configurations.

Makes the random corridor joining routine obey unjoined areas.

Fixes a bug in shopkeeper naming routine, where multiple shops
of the same type on the same level might reuse the shopkeeper name.

This is modified and consolidated commit from xNetHack by
copperwater <aosdict@gmail.com>.
This commit is contained in:
Pasi Kallinen
2020-12-19 13:11:36 +02:00
parent 803119a72b
commit 44f4085f69
3 changed files with 90 additions and 4 deletions

View File

@@ -545,6 +545,59 @@ xx|.....|xx
end });
end,
-- Twin businesses
{
mindiff = 4; -- arbitrary
contents = function()
-- Due to the way room connections work in mklev.c, we must guarantee
-- that the "aisle" between the shops touches all four walls of the
-- larger room. Thus it has an extra width and height.
des.room({ type="themed", w=9, h=5, contents = function()
-- There are eight possible placements of the two shops, four of
-- which have the vertical aisle in the center.
southeast = function() return percent(50) and "south" or "east" end
northeast = function() return percent(50) and "north" or "east" end
northwest = function() return percent(50) and "north" or "west" end
southwest = function() return percent(50) and "south" or "west" end
placements = {
{ lx = 1, ly = 1, rx = 4, ry = 1, lwall = "south", rwall = southeast() },
{ lx = 1, ly = 2, rx = 4, ry = 2, lwall = "north", rwall = northeast() },
{ lx = 1, ly = 1, rx = 5, ry = 1, lwall = southeast(), rwall = southwest() },
{ lx = 1, ly = 1, rx = 5, ry = 2, lwall = southeast(), rwall = northwest() },
{ lx = 1, ly = 2, rx = 5, ry = 1, lwall = northeast(), rwall = southwest() },
{ lx = 1, ly = 2, rx = 5, ry = 2, lwall = northeast(), rwall = northwest() },
{ lx = 2, ly = 1, rx = 5, ry = 1, lwall = southwest(), rwall = "south" },
{ lx = 2, ly = 2, rx = 5, ry = 2, lwall = northwest(), rwall = "north" }
}
ltype,rtype = "weapon shop","armor shop"
if percent(50) then
ltype,rtype = rtype,ltype
end
shopdoorstate = function()
if percent(1) then
return "locked"
elseif percent(50) then
return "closed"
else
return "open"
end
end
p = placements[d(#placements)]
des.room({ type=ltype, x=p["lx"], y=p["ly"], w=3, h=3, filled=1, joined=0,
contents = function()
des.door({ state=shopdoorstate(), wall=p["lwall"] })
end
});
des.room({ type=rtype, x=p["rx"], y=p["ry"], w=3, h=3, filled=1, joined=0,
contents = function()
des.door({ state=shopdoorstate(), wall=p["rwall"] })
end
});
end
});
end
},
};
function is_eligible(room)

View File

@@ -35,6 +35,7 @@ static void FDECL(do_room_or_subroom, (struct mkroom *, int, int,
int, int, BOOLEAN_P,
SCHAR_P, BOOLEAN_P, BOOLEAN_P));
static void NDECL(makerooms);
static boolean FDECL(door_into_nonjoined, (XCHAR_P, XCHAR_P));
static void FDECL(finddpos, (coord *, XCHAR_P, XCHAR_P,
XCHAR_P, XCHAR_P));
static void FDECL(mkinvpos, (XCHAR_P, XCHAR_P, int));
@@ -68,6 +69,33 @@ const genericptr vy;
#endif /* LINT */
}
/* Return TRUE if a door placed at (x, y) which otherwise passes okdoor() checks
* would be connecting into an area that was declared as joined = 0.
* Checking for this in finddpos() enables us to have rooms with sub-areas (such
* as shops) that will never randomly generate unwanted doors in order to
* connect them up to other areas.
*/
static boolean
door_into_nonjoined(x, y)
xchar x, y;
{
xchar tx, ty, diridx;
for (diridx = 0; diridx <= 6; diridx += 2) {
tx = x + xdir[diridx];
ty = y + ydir[diridx];
if (!isok(tx, ty) || IS_ROCK(levl[tx][ty].typ))
continue;
/* Is this connecting to a room that doesn't want joining? */
if (levl[tx][ty].roomno >= ROOMOFFSET &&
!g.rooms[levl[tx][ty].roomno - ROOMOFFSET].needjoining) {
return TRUE;
}
}
return FALSE;
}
static void
finddpos(cc, xl, yl, xh, yh)
coord *cc;
@@ -77,12 +105,12 @@ xchar xl, yl, xh, yh;
x = rn1(xh - xl + 1, xl);
y = rn1(yh - yl + 1, yl);
if (okdoor(x, y))
if (okdoor(x, y) && !door_into_nonjoined(x, y))
goto gotit;
for (x = xl; x <= xh; x++)
for (y = yl; y <= yh; y++)
if (okdoor(x, y))
if (okdoor(x, y) && !door_into_nonjoined(x, y))
goto gotit;
for (x = xl; x <= xh; x++)
@@ -92,6 +120,8 @@ xchar xl, yl, xh, yh;
/* cannot find something reasonable -- strange */
x = xl;
y = yh;
impossible("finddpos: couldn't find door pos within (%d,%d,%d,%d)",
xl, yl, xh, yh);
gotit:
cc->x = x;
cc->y = y;

View File

@@ -495,7 +495,7 @@ const char *const *nlp;
int i, trycnt, names_avail;
const char *shname = 0;
struct monst *mtmp;
int name_wanted;
int name_wanted = shk->m_id;
s_level *sptr;
if (nlp == shklight && In_mines(&u.uz)
@@ -510,7 +510,7 @@ const char *const *nlp;
use ledger_no rather than depth to keep minetown distinct. */
int nseed = (int) ((long) ubirthday / 257L);
name_wanted = ledger_no(&u.uz) + (nseed % 13) - (nseed % 5);
name_wanted += ledger_no(&u.uz) + (nseed % 13) - (nseed % 5);
if (name_wanted < 0)
name_wanted += (13 + 5);
shk->female = name_wanted & 1;
@@ -518,6 +518,8 @@ const char *const *nlp;
for (names_avail = 0; nlp[names_avail]; names_avail++)
continue;
name_wanted = name_wanted % names_avail;
for (trycnt = 0; trycnt < 50; trycnt++) {
if (nlp == shktools) {
shname = shktools[rn2(names_avail)];
@@ -545,6 +547,7 @@ const char *const *nlp;
continue;
if (strcmp(ESHK(mtmp)->shknam, shname))
continue;
name_wanted = names_avail; /* try a random name */
break;
}
if (!mtmp)