]> granicus.if.org Git - nethack/commitdiff
Add a new themed room: "Twin business"
authorPasi Kallinen <paxed@alt.org>
Sat, 19 Dec 2020 11:11:36 +0000 (13:11 +0200)
committerPasi Kallinen <paxed@alt.org>
Sat, 19 Dec 2020 11:45:35 +0000 (13:45 +0200)
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>.

dat/themerms.lua
src/mklev.c
src/shknam.c

index 4f4f59029ef6331295e7c612c59e9ead814ea4f8..fa85a44dfc9c7361fb124cc7e44a003c8f18b4d6 100644 (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)
index bfb0c085cb135a6af69ff1f6ac5f42e3cbd1c53e..51616aaf4b960758a11c90000b9994689ae47819 100644 (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;
index 69b217ffb443f00a7873582b3e02e0c789dee672..b8a4386c41535d0791459b0d4e0e11f6af45ffec 100644 (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)