From 98a10d262e66e2ab7e0dd7094252b49c77f37059 Mon Sep 17 00:00:00 2001 From: Anders Jenbo Date: Sun, 12 Jun 2022 10:27:52 +0200 Subject: [PATCH] Unify PlaceMiniSet --- Source/drlg_l1.cpp | 115 +++++++++++++--------------------------- Source/drlg_l2.cpp | 52 ++++-------------- Source/drlg_l3.cpp | 68 +++++++++--------------- Source/drlg_l4.cpp | 73 ++++++++----------------- Source/engine/point.hpp | 8 +++ Source/gendung.cpp | 50 ++++++++++++++++- Source/gendung.h | 5 ++ Source/objects.cpp | 2 +- 8 files changed, 159 insertions(+), 214 deletions(-) diff --git a/Source/drlg_l1.cpp b/Source/drlg_l1.cpp index 2081018c0..145bef576 100644 --- a/Source/drlg_l1.cpp +++ b/Source/drlg_l1.cpp @@ -741,64 +741,6 @@ void ApplyShadowsPatterns() } } -bool PlaceMiniSet(const Miniset &miniset, bool setview) -{ - int sw = miniset.size.width; - int sh = miniset.size.height; - int sx = GenerateRnd(DMAXX - sw) - 1; - int sy = GenerateRnd(DMAXY - sh); - - for (int bailcnt = 0;; bailcnt++) { - if (bailcnt > 4000) - return false; - - sx++; - if (sx == DMAXX - sw) { - sx = 0; - sy++; - if (sy == DMAXY - sh) { - sy = 0; - } - } - - // Limit the position of SetPieces for compatibility with Diablo bug - bool valid = true; - if (sx <= 12) { - sx++; - valid = false; - } - if (sy <= 12) { - sy++; - valid = false; - } - if (!valid) { - continue; - } - - if (SetPiecesRoom.Contains({ sx, sy })) - continue; - if (miniset.matches({ sx, sy })) - break; - } - - miniset.place({ sx, sy }); - - if (&miniset == &PWATERIN) { - int8_t t = TransVal; - TransVal = 0; - DRLG_MRectTrans(sx, sy + 2, sx + 5, sy + 4); - TransVal = t; - - Quests[Q_PWATER].position = { 2 * sx + 21, 2 * sy + 22 }; - } - - if (setview) { - ViewPosition = Point { 19, 20 } + Displacement { sx, sy } * 2; - } - - return true; -} - bool CanReplaceTile(uint8_t replace, Point tile) { if (replace < 84 || replace > 100) { @@ -2048,30 +1990,46 @@ void CryptFloor(int rndper) bool PlaceCathedralStairs(lvl_entry entry) { bool success = true; + std::optional position; // Place poison water entrance if (Quests[Q_PWATER].IsAvailable()) { - if (!PlaceMiniSet(PWATERIN, entry == ENTRY_RTNLVL)) + position = PlaceMiniSet(PWATERIN, 4000, true); + if (!position) { success = false; - if (entry == ENTRY_RTNLVL) - ViewPosition += Displacement { 2, 3 }; + } else { + int8_t t = TransVal; + TransVal = 0; + Point miniPosition = *position; + DRLG_MRectTrans(miniPosition.x, miniPosition.y + 2, miniPosition.x + 5, miniPosition.y + 4); + TransVal = t; + Quests[Q_PWATER].position = miniPosition.megaToWorld() + Displacement { 5, 7 }; + if (entry == ENTRY_RTNLVL) + ViewPosition = Quests[Q_PWATER].position; + } } // Place stairs up - if (!PlaceMiniSet(MyPlayer->pOriginalCathedral ? L5STAIRSUP : STAIRSUP, entry == ENTRY_MAIN)) { + position = PlaceMiniSet(MyPlayer->pOriginalCathedral ? L5STAIRSUP : STAIRSUP, 4000, true); + if (!position) { if (MyPlayer->pOriginalCathedral) return false; success = false; + } else if (entry == ENTRY_MAIN) { + ViewPosition = position->megaToWorld() + Displacement { 3, 4 }; } // Place stairs down - if (!Quests[Q_LTBANNER].IsAvailable() && !PlaceMiniSet(STAIRSDOWN, entry == ENTRY_PREV)) - success = false; - if (entry == ENTRY_PREV) { - if (Quests[Q_LTBANNER].IsAvailable()) - ViewPosition = Point { 20, 28 } + Displacement { setpc_x, setpc_y } * 2; - else - ViewPosition.y--; + if (Quests[Q_LTBANNER].IsAvailable()) { + if (entry == ENTRY_PREV) + ViewPosition = Point(setpc_x, setpc_y).megaToWorld() + Displacement { 4, 12 }; + } else { + position = PlaceMiniSet(STAIRSDOWN, 4000, true); + if (!position) { + success = false; + } else if (entry == ENTRY_PREV) { + ViewPosition = position->megaToWorld() + Displacement { 3, 3 }; + } } return success; @@ -2080,20 +2038,23 @@ bool PlaceCathedralStairs(lvl_entry entry) bool PlaceCryptStairs(lvl_entry entry) { bool success = true; + std::optional position; // Place stairs up - bool enteringFromAbove = entry == ENTRY_MAIN || entry == ENTRY_TWARPDN; - if (!PlaceMiniSet(currlevel != 21 ? L5STAIRSUPHF : L5STAIRSTOWN, enteringFromAbove)) + position = PlaceMiniSet(currlevel != 21 ? L5STAIRSUPHF : L5STAIRSTOWN, 4000, true); + if (!position) { success = false; - if (enteringFromAbove) - ViewPosition.y++; + } else if (entry == ENTRY_MAIN || entry == ENTRY_TWARPDN) { + ViewPosition = position->megaToWorld() + Displacement { 3, 5 }; + } // Place stairs down if (currlevel != 24) { - if (!PlaceMiniSet(L5STAIRSDOWN, entry == ENTRY_PREV)) + position = PlaceMiniSet(L5STAIRSDOWN, 4000, true); + if (!position) success = false; - if (entry == ENTRY_PREV) - ViewPosition.y += 3; + else if (entry == ENTRY_PREV) + ViewPosition = position->megaToWorld() + Displacement { 3, 7 }; } return success; @@ -2211,7 +2172,7 @@ void GenerateLevel(lvl_entry entry) int numt = GenerateRnd(5) + 5; for (int i = 0; i < numt; i++) { - PlaceMiniSet(LAMPS, false); + PlaceMiniSet(LAMPS, 4000, true); } FillFloor(); diff --git a/Source/drlg_l2.cpp b/Source/drlg_l2.cpp index 1150e84c4..078e7f967 100644 --- a/Source/drlg_l2.cpp +++ b/Source/drlg_l2.cpp @@ -1571,41 +1571,6 @@ void ApplyShadowsPatterns() } } -bool PlaceMiniSet(const Miniset &miniset, bool setview) -{ - int sw = miniset.size.width; - int sh = miniset.size.height; - int sx = GenerateRnd(DMAXX - sw) - 1; - int sy = GenerateRnd(DMAXY - sh); - - for (int bailcnt = 0;; bailcnt++) { - if (bailcnt > 198) - return false; - - sx++; - if (sx == DMAXX - sw) { - sx = 0; - sy++; - if (sy == DMAXY - sh) { - sy = 0; - } - } - - if (SetPiecesRoom.Contains({ sx, sy })) - continue; - if (miniset.matches({ sx, sy })) - break; - } - - miniset.place({ sx, sy }); - - if (setview) { - ViewPosition = Point { 21, 22 } + Displacement { sx, sy } * 2; - } - - return true; -} - void PlaceMiniSetRandom(const Miniset &miniset, int rndper) { int sw = miniset.size.width; @@ -2772,24 +2737,29 @@ void FixDoors() bool PlaceStairs(lvl_entry entry) { + std::optional position; + // Place stairs up - if (!PlaceMiniSet(USTAIRS, entry == ENTRY_MAIN)) + position = PlaceMiniSet(USTAIRS); + if (!position) return false; if (entry == ENTRY_MAIN) - ViewPosition.y -= 2; + ViewPosition = position->megaToWorld() + Displacement { 5, 4 }; // Place stairs down - if (!PlaceMiniSet(DSTAIRS, entry == ENTRY_PREV)) + position = PlaceMiniSet(DSTAIRS); + if (!position) return false; if (entry == ENTRY_PREV) - ViewPosition.x--; + ViewPosition = position->megaToWorld() + Displacement { 4, 6 }; // Place town warp stairs if (currlevel == 5) { - if (!PlaceMiniSet(WARPSTAIRS, entry == ENTRY_TWARPDN)) + position = PlaceMiniSet(WARPSTAIRS); + if (!position) return false; if (entry == ENTRY_TWARPDN) - ViewPosition.y -= 2; + ViewPosition = position->megaToWorld() + Displacement { 5, 4 }; } return true; diff --git a/Source/drlg_l3.cpp b/Source/drlg_l3.cpp index 61c0d9be4..195298d50 100644 --- a/Source/drlg_l3.cpp +++ b/Source/drlg_l3.cpp @@ -1375,41 +1375,6 @@ bool Spawn(int x, int y, int *totarea) return false; } -bool PlaceMiniSet(const Miniset &miniset, bool setview) -{ - int sw = miniset.size.width; - int sh = miniset.size.height; - int sx = GenerateRnd(DMAXX - sw) - 1; - int sy = GenerateRnd(DMAXY - sh); - - for (int bailcnt = 0;; bailcnt++) { - if (bailcnt > 198) - return false; - - sx++; - if (sx == DMAXX - sw) { - sx = 0; - sy++; - if (sy == DMAXY - sh) { - sy = 0; - } - } - - if (SetPiecesRoom.Contains({ sx, sy })) - continue; - if (miniset.matches({ sx, sy })) - break; - } - - miniset.place({ sx, sy }); - - if (setview) { - ViewPosition = Point { 17, 19 } + Displacement { sx, sy } * 2; - } - - return true; -} - bool CanReplaceTile(uint8_t replace, Point tile) { if (replace < 84 || replace > 100) { @@ -2018,35 +1983,52 @@ bool Lockout() bool PlaceCaveStairs(lvl_entry entry) { + std::optional position; + // Place stairs up - if (!PlaceMiniSet(L3UP, entry == ENTRY_MAIN)) + position = PlaceMiniSet(L3UP); + if (!position) return false; + if (entry == ENTRY_MAIN) + ViewPosition = position->megaToWorld() + Displacement { 1, 3 }; // Place stairs down - if (!PlaceMiniSet(L3DOWN, entry == ENTRY_PREV)) + position = PlaceMiniSet(L3DOWN); + if (!position) return false; if (entry == ENTRY_PREV) - ViewPosition += { 2, -2 }; + ViewPosition = position->megaToWorld() + Displacement { 3, 1 }; // Place town warp stairs - if (currlevel == 9 && !PlaceMiniSet(L3HOLDWARP, entry == ENTRY_TWARPDN)) - return false; + if (currlevel == 9) { + position = PlaceMiniSet(L3HOLDWARP); + if (!position) + return false; + if (entry == ENTRY_TWARPDN) + ViewPosition = position->megaToWorld() + Displacement { 1, 3 }; + } return true; } bool PlaceNestStairs(lvl_entry entry) { + std::optional position; + // Place stairs up - if (!PlaceMiniSet(currlevel != 17 ? L6UP : L6HOLDWARP, entry == ENTRY_MAIN || entry == ENTRY_TWARPDN)) + position = PlaceMiniSet(currlevel != 17 ? L6UP : L6HOLDWARP); + if (!position) return false; + if (entry == ENTRY_MAIN || entry == ENTRY_TWARPDN) + ViewPosition = position->megaToWorld() + Displacement { 1, 3 }; // Place stairs down if (currlevel != 20) { - if (!PlaceMiniSet(L6DOWN, entry == ENTRY_PREV)) + position = PlaceMiniSet(L6DOWN); + if (!position) return false; if (entry == ENTRY_PREV) - ViewPosition += { 2, -2 }; + ViewPosition = position->megaToWorld() + Displacement { 3, 1 }; } return true; diff --git a/Source/drlg_l4.cpp b/Source/drlg_l4.cpp index c7e9599ee..46d9514f2 100644 --- a/Source/drlg_l4.cpp +++ b/Source/drlg_l4.cpp @@ -164,41 +164,6 @@ void ApplyShadowsPatterns() } } -bool PlaceMiniSet(const Miniset &miniset, bool setview) -{ - int sw = miniset.size.width; - int sh = miniset.size.height; - int sx = GenerateRnd(DMAXX - sw) - 1; - int sy = GenerateRnd(DMAXY - sh); - - for (int bailcnt = 0;; bailcnt++) { - if (bailcnt > 198) - return false; - - sx++; - if (sx == DMAXX - sw) { - sx = 0; - sy++; - if (sy == DMAXY - sh) { - sy = 0; - } - } - - if (SetPiecesRoom.Contains({ sx, sy })) - continue; - if (miniset.matches({ sx, sy })) - break; - } - - miniset.place({ sx, sy }, true); - - if (setview) { - ViewPosition = Point { 21, 22 } + Displacement { sx, sy } * 2; - } - - return true; -} - void LoadQuestSetPieces() { setloadflag = false; @@ -1236,38 +1201,46 @@ void GeneralFix() bool PlaceStairs(lvl_entry entry) { + std::optional position; + // Place stairs up - if (!PlaceMiniSet(L4USTAIRS, entry == ENTRY_MAIN)) + position = PlaceMiniSet(L4USTAIRS); + if (!position) return false; if (entry == ENTRY_MAIN) - ViewPosition.x++; + ViewPosition = position->megaToWorld() + Displacement { 6, 6 }; if (currlevel != 15) { // Place stairs down - if (currlevel != 16 && !Quests[Q_WARLORD].IsAvailable()) { - if (!PlaceMiniSet(L4DSTAIRS, entry == ENTRY_PREV)) - return false; + if (currlevel != 16) { + if (Quests[Q_WARLORD].IsAvailable()) { + if (entry == ENTRY_PREV) + ViewPosition = Point(setpc_x, setpc_y).megaToWorld() + Displacement { 6, 6 }; + } else { + position = PlaceMiniSet(L4DSTAIRS); + if (!position) + return false; + if (entry == ENTRY_PREV) + ViewPosition = position->megaToWorld() + Displacement { 5, 7 }; + } } // Place town warp stairs if (currlevel == 13) { - if (!PlaceMiniSet(L4TWARP, entry == ENTRY_TWARPDN)) + position = PlaceMiniSet(L4TWARP); + if (!position) return false; if (entry == ENTRY_TWARPDN) - ViewPosition.x++; + ViewPosition = position->megaToWorld() + Displacement { 6, 6 }; } } else { // Place hell gate bool isGateOpen = gbIsMultiplayer || Quests[Q_DIABLO]._qactive == QUEST_ACTIVE; - if (!PlaceMiniSet(isGateOpen ? L4PENTA2 : L4PENTA, entry == ENTRY_PREV)) + position = PlaceMiniSet(isGateOpen ? L4PENTA2 : L4PENTA); + if (!position) return false; - } - - if (entry == ENTRY_PREV) { - if (Quests[Q_WARLORD].IsAvailable()) - ViewPosition = Point { 22, 22 } + Displacement { setpc_x, setpc_y } * 2; - else - ViewPosition.y++; + if (entry == ENTRY_PREV) + ViewPosition = position->megaToWorld() + Displacement { 5, 7 }; } return true; diff --git a/Source/engine/point.hpp b/Source/engine/point.hpp index 7398da791..227dd396d 100644 --- a/Source/engine/point.hpp +++ b/Source/engine/point.hpp @@ -161,6 +161,14 @@ struct Point { return std::max(offset.deltaX, offset.deltaY); } + /** + * @brief Converte from mega tile cordinates to dungeon piece cordinates + */ + constexpr Point megaToWorld() + { + return { 16 + 2 * x, 16 + 2 * y }; + } + #ifdef BUILD_TESTING /** * @brief Format points nicely in test failure messages diff --git a/Source/gendung.cpp b/Source/gendung.cpp index 4447dc077..21bbfec4a 100644 --- a/Source/gendung.cpp +++ b/Source/gendung.cpp @@ -489,8 +489,8 @@ void DRLG_RectTrans(int x1, int y1, int x2, int y2) void DRLG_MRectTrans(int x1, int y1, int x2, int y2) { - x1 = 2 * x1 + 17; - y1 = 2 * y1 + 17; + x1 = 2 * x1 + 16 + 1; + y1 = 2 * y1 + 16 + 1; x2 = 2 * x2 + 16; y2 = 2 * y2 + 16; @@ -563,6 +563,52 @@ void Make_SetPC(int x, int y, int w, int h) } } +std::optional PlaceMiniSet(const Miniset &miniset, int tries, bool drlg1Quirk) +{ + int sw = miniset.size.width; + int sh = miniset.size.height; + int sx = GenerateRnd(DMAXX - sw); + int sy = GenerateRnd(DMAXY - sh); + + for (int bailcnt = 0;; bailcnt++, sx++) { + if (bailcnt > tries) + return {}; + + if (sx == DMAXX - sw) { + sx = 0; + sy++; + if (sy == DMAXY - sh) { + sy = 0; + } + } + + // Limit the position of SetPieces for compatibility with Diablo bug + if (drlg1Quirk) { + bool valid = true; + if (sx <= 12) { + sx++; + valid = false; + } + if (sy <= 12) { + sy++; + valid = false; + } + if (!valid) { + continue; + } + } + + if (SetPiecesRoom.Contains({ sx, sy })) + continue; + if (miniset.matches({ sx, sy })) + break; + } + + miniset.place({ sx, sy }); + + return Point(sx, sy); +} + void DRLG_PlaceThemeRooms(int minSize, int maxSize, int floor, int freq, bool rndSize) { themeCount = 0; diff --git a/Source/gendung.h b/Source/gendung.h index 7b90b08a0..b74c2fa3e 100644 --- a/Source/gendung.h +++ b/Source/gendung.h @@ -338,6 +338,11 @@ void DRLG_AreaTrans(int num, BYTE *List); void DRLG_InitSetPC(); void DRLG_SetPC(); void Make_SetPC(int x, int y, int w, int h); +/** + * @param tries Tiles to try, 1600 will scan the full map + * @param drlg1Quirk Match buggy behaviour of Diablo's Cathedral + */ +std::optional PlaceMiniSet(const Miniset &miniset, int tries = 198, bool drlg1Quirk = false); void DRLG_PlaceThemeRooms(int minSize, int maxSize, int floor, int freq, bool rndSize); void DRLG_HoldThemeRooms(); void DRLG_LPass3(int lv); diff --git a/Source/objects.cpp b/Source/objects.cpp index 16adfcd36..a7947fb27 100644 --- a/Source/objects.cpp +++ b/Source/objects.cpp @@ -1612,7 +1612,7 @@ void ObjSetMini(Point position, int v) { MegaTile mega = pMegaTiles[v - 1]; - Point megaOrigin = position * 2 + Displacement { 16, 16 }; + Point megaOrigin = position.megaToWorld(); ObjSetMicro(megaOrigin, SDL_SwapLE16(mega.micro1) + 1); ObjSetMicro(megaOrigin + Direction::SouthEast, SDL_SwapLE16(mega.micro2) + 1);