From 848222b8f33940d53fdd441638517d57dc3004be Mon Sep 17 00:00:00 2001 From: Anders Jenbo Date: Thu, 2 Jun 2022 14:18:14 +0200 Subject: [PATCH] Test Catacomb level generation (#4651) --- test/CMakeLists.txt | 1 + test/drlg_l1_test.cpp | 6 +- test/drlg_l2_test.cpp | 90 ++++++++++++++++++++++++++ test/fixtures/diablo/5-1677631846.dun | Bin 0 -> 54404 bytes test/fixtures/diablo/6-2034738122.dun | Bin 0 -> 54404 bytes test/fixtures/diablo/7-680552750.dun | Bin 0 -> 54404 bytes test/fixtures/diablo/8-1999936419.dun | Bin 0 -> 54404 bytes 7 files changed, 94 insertions(+), 3 deletions(-) create mode 100644 test/drlg_l2_test.cpp create mode 100644 test/fixtures/diablo/5-1677631846.dun create mode 100644 test/fixtures/diablo/6-2034738122.dun create mode 100644 test/fixtures/diablo/7-680552750.dun create mode 100644 test/fixtures/diablo/8-1999936419.dun diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 2405adc39..2dd6f7f7b 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -20,6 +20,7 @@ set(tests diablo_test drlg_common_test drlg_l1_test + drlg_l2_test effects_test file_util_test inv_test diff --git a/test/drlg_l1_test.cpp b/test/drlg_l1_test.cpp index 005f61fdf..e6ec81d6b 100644 --- a/test/drlg_l1_test.cpp +++ b/test/drlg_l1_test.cpp @@ -35,7 +35,7 @@ void TestCreateL5Dungeon(bool hellfire, int level, uint32_t seed, lvl_entry entr pMegaTiles = std::make_unique(206); leveltype = DTYPE_CATHEDRAL; } else if (level >= 21 && level <= 24) { - pMegaTiles = std::make_unique(216); + pMegaTiles = std::make_unique(217); leveltype = DTYPE_CRYPT; } @@ -60,7 +60,7 @@ void TestCreateL5Dungeon(bool hellfire, int level, uint32_t seed, lvl_entry entr for (int x = 0; x < DMAXX; x++) { auto tileId = static_cast(SDL_SwapLE16(*tileLayer)); tileLayer++; - ASSERT_EQ(dungeon[x][y], tileId); + ASSERT_EQ(dungeon[x][y], tileId) << "Tiles don't match at " << x << "x" << y; } } @@ -70,7 +70,7 @@ void TestCreateL5Dungeon(bool hellfire, int level, uint32_t seed, lvl_entry entr for (int x = 16; x < 16 + DMAXX * 2; x++) { auto sectorId = static_cast(SDL_SwapLE16(*transparentLayer)); transparentLayer++; - ASSERT_EQ(dTransVal[x][y], sectorId) << "Room/region indexes don't match"; + ASSERT_EQ(dTransVal[x][y], sectorId) << "Room/region indexes don't match at " << x << "x" << y; } } } diff --git a/test/drlg_l2_test.cpp b/test/drlg_l2_test.cpp new file mode 100644 index 000000000..9b9cc13f3 --- /dev/null +++ b/test/drlg_l2_test.cpp @@ -0,0 +1,90 @@ +#include +#include + +#include "drlg_l2.h" +#include "engine/load_file.hpp" +#include "gendung.h" +#include "utils/paths.h" + +using namespace devilution; + +namespace { + +void TestCreateL2Dungeon(int level, uint32_t seed, lvl_entry entry) +{ + pMegaTiles = std::make_unique(160); + leveltype = DTYPE_CATACOMBS; + + currlevel = level; + CreateL2Dungeon(seed, entry); + + std::string path = paths::BasePath(); + + paths::SetPrefPath(path); + std::string dunPath = fmt::format("../test/fixtures/diablo/{}-{}.dun", level, seed); + auto dunData = LoadFileInMem(dunPath.c_str()); + ASSERT_EQ(DMAXX, dunData[0]); + ASSERT_EQ(DMAXY, dunData[1]); + + const uint16_t *tileLayer = &dunData[2]; + + for (int y = 0; y < DMAXY; y++) { + for (int x = 0; x < DMAXX; x++) { + auto tileId = static_cast(SDL_SwapLE16(*tileLayer)); + tileLayer++; + ASSERT_EQ(dungeon[x][y], tileId) << "Tiles don't match at " << x << "x" << y; + } + } + + const uint16_t *transparentLayer = &dunData[2 + DMAXX * DMAXY * 13]; + + for (int y = 16; y < 16 + DMAXY * 2; y++) { + for (int x = 16; x < 16 + DMAXX * 2; x++) { + auto sectorId = static_cast(SDL_SwapLE16(*transparentLayer)); + transparentLayer++; + ASSERT_EQ(dTransVal[x][y], sectorId) << "Room/region indexes don't match at " << x << "x" << y; + } + } +} + +TEST(Drlg_l1, CreateL2Dungeon_diablo_5_1677631846) +{ + TestCreateL2Dungeon(5, 1677631846, ENTRY_MAIN); + EXPECT_EQ(ViewPosition.x, 27); + EXPECT_EQ(ViewPosition.y, 28); + TestCreateL2Dungeon(5, 1677631846, ENTRY_PREV); + EXPECT_EQ(ViewPosition.x, 26); + EXPECT_EQ(ViewPosition.y, 62); +} + +TEST(Drlg_l1, CreateL2Dungeon_diablo_6_2034738122) +{ + TestCreateL2Dungeon(6, 2034738122, ENTRY_MAIN); + EXPECT_EQ(ViewPosition.x, 33); + EXPECT_EQ(ViewPosition.y, 26); + TestCreateL2Dungeon(6, 2034738122, ENTRY_PREV); + EXPECT_EQ(ViewPosition.x, 34); + EXPECT_EQ(ViewPosition.y, 52); +} + +TEST(Drlg_l1, CreateL2Dungeon_diablo_7_680552750) +{ + TestCreateL2Dungeon(7, 680552750, ENTRY_MAIN); + EXPECT_EQ(ViewPosition.x, 27); + EXPECT_EQ(ViewPosition.y, 26); + TestCreateL2Dungeon(7, 680552750, ENTRY_PREV); + EXPECT_EQ(ViewPosition.x, 78); + EXPECT_EQ(ViewPosition.y, 52); +} + +TEST(Drlg_l1, CreateL2Dungeon_diablo_8_1999936419) +{ + TestCreateL2Dungeon(8, 1999936419, ENTRY_MAIN); + EXPECT_EQ(ViewPosition.x, 39); + EXPECT_EQ(ViewPosition.y, 74); + TestCreateL2Dungeon(8, 1999936419, ENTRY_PREV); + EXPECT_EQ(ViewPosition.x, 48); + EXPECT_EQ(ViewPosition.y, 46); +} + +} // namespace diff --git a/test/fixtures/diablo/5-1677631846.dun b/test/fixtures/diablo/5-1677631846.dun new file mode 100644 index 0000000000000000000000000000000000000000..f31c5084f994471f878caba965c65963737db31c GIT binary patch literal 54404 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 Mt#?5e1^TDJ|4h>*xc~qF literal 0 HcmV?d00001 diff --git a/test/fixtures/diablo/6-2034738122.dun b/test/fixtures/diablo/6-2034738122.dun new file mode 100644 index 0000000000000000000000000000000000000000..1013ed86197c22036ec3a1f561dd4c6268fb6864 GIT binary patch literal 54404 zcmeI5>24fF5XZ}2J9ZK$P9!4`g5*Oa$OjG+B%Xi>gb0dr+kS#1g4_;-aD+f05)#O~ zFkM|!Tir9=bL||xc5TZueOCYa-_^&if;bQ7VQp^0O;|MHI{Xa3nCBww!BhBe2KoiK z3lk^YhE4cq276n^)|YU}Ja1aQ6}SLL4JY#c1+U>N8+*4l^JQb{YsX%_z_l3{c9QX1jrthy82MQ_{+kS;JLAP z7p_>V*aGeE*c8UZ-m0a;SzMXsi#=?Qt?t5t8Rx`2x8Ya#&BV|?h39sTkQXg5<0jzP zihK`jt4&ky6Zi<;GN~8v(melwKQkSd>>M32c}wOG?cFhdpThg*S+sZGY2wic=XrQIl;m z)_vne%chS-!whyPKYl-{~>+uY*y>&zB2V~xz&dQFNkBfG$WVCCJKM03gEYP@UF?g+TTs4uLKHh3N8?V+FJzJ&A3 zf$LCTxVoO0KlJlW_}tXQa^5kxE~|~Jnbs3qn@o3RvbSZdJkItQS*=)x{++iM@-o(U z!?4_ecd|8){o!i8W&1-u^zXbq<_x{xv%bHQt$9+A=M(u*(fant+m6AyUCX>)x&2nQ zi*Y){!+p|j&MnCv?zd<}Z*+Kqk%rH+ z9gLNbUHtNNWg#t}a(pYovlGv7S}6|l`&zP6u*uOO`Fi;&{X?Vg*Jb#Yz4ksFNjN8OL znQQj{2K}f4s(>n>3aA3AfGVI0r~;~hDxeCe0;+&2pbDr0s(>n>3aA3AfGVI0r~;~h zDxeCe0;+&2pbDr0s(>n>3aA3AfGVI0r~;~hDxeCe0;+&2pbDr0s(>n>3aA1l3Y;DSJkFY zd3cwR-Y_PqIu^UFgZjn$ADb>bR+>|yjiUA%Udn$zpN~8 zr)j#%Hmg`xkIVSol%cG?Z}V)RDtV*SV`8Zq^S@$EY14I#`NI1lmv-H2%wCZ~2!>Q8 z##hW2J}mQ7#oC%P4+?Z~|L9|!A+Fe}I1AxDDP*G$);2bgZEU`nWE#@JFh zQDe6}{Edd#$0Uu@;ar|G>tiF?y9w!5K7uhkQu{m@3XE|^HBl~wlc9`P`O4HOFN>XO z<*kM*O_wk2^MG_CM)w{%+{~5#*1+>hgq&(lN8bTtE+p36mfNB$&6p2wIPFL2l64zD zll^MNY^mwj{oYP9+tvJbeRjLwX}g_ioZn*n%>K)@7s{c0q#J}P4dKZ6dV?W=<)rfn@*9oVa)ehUJ%5~|g>JDFy zbbS%V{h*~<$DlF&Yt#|Ufm!cGZDc%1H=r@}YoqxvZR*^`>(m*B zw!9bJW6Sl?(mD!s`#VKdk9Y_Etg4bzz6Vd8REp7I^&3KgdD;JbEmEI{)cx33bDmS} zf9Y>CNBZv?#8=W;gP}c)>F^9n^S2l#6h%{xg)~l?SJ~!80slMey!%<`ds--OUS_8) z=V2UkTdlO6DxeCe0*6n51*jLsQl=gq)*9z?Q254C4}#uz5+u~umuhxBj!^$XcQVKy zY9o2w5{g}kb;Y*`)uC!MLM5>w`4%exg-T*oeCtpQ(poyKRu5~Gf5fiD4jbPoCF4$liXSvS)-n8U zzQ2StbMu<&7v|#JBA?q=SzLAsiIvsQmoY*4yFH)#og?3Oopd=DmyXAWJ?FNxMln$jW8qJ}O*|cLUzQuUrF><&aaqdxRk30DnEp3! ze6*SYmU026DzaDj?>gh8I)1yVRM9TA$nz~#7%JL{$szcJ4P*F01;giW8hjQqcz!4!Y2!YN^EtVbJ;K+rjpz~`Hnl=RGy2|LK2S6$_IA;gTU#5JEDA;C;tvp zRppA^d@R2|^Zg~XKaar&x%*#we0fDFosNF(_}Z`FkS~TA%5tmpD{DJUS%`3$p0$^@ G3j7ZWcs23> literal 0 HcmV?d00001 diff --git a/test/fixtures/diablo/7-680552750.dun b/test/fixtures/diablo/7-680552750.dun new file mode 100644 index 0000000000000000000000000000000000000000..b49804292b320e6667cade1998f7f1dd3fa6d0c1 GIT binary patch literal 54404 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 literal 0 HcmV?d00001 diff --git a/test/fixtures/diablo/8-1999936419.dun b/test/fixtures/diablo/8-1999936419.dun new file mode 100644 index 0000000000000000000000000000000000000000..1a8daaa2a6f45faba590138f4488323753879cd5 GIT binary patch literal 54404 zcmeHQd5=^@5U-h8*xLny{y~h1{~(DMLi7_Dk3GfwcqFmS7BT!Qb#g{eA|&z*X3Ue> z`k{v7l?r=H%I8?MNAMW70`DWWA2E)#&K4}zuy+~m!F{E-qkcl~50&I+EyuO9fcC5K zp^j9^Q*I;%q^Ci0!ue*@c%LJ0}&UOG<9q$MAug`x>#m4S1zEI-O*(=MjZGG}(#m=&3hdVXJgHD7 zM(-?q$>?F7Aj1m^{kF2brJ|O~ZPdkfOaDFx->N?JOF4tNP5Kw%dZdT=EPuP&BH9kw z9_hG#uW}pn@fv&rA9=N6c*Ts{ggBP3;8>B>+d2!0x0}ia=HsTiML$%zXwNayY~Iy1 z5uVM>_)9w4rfw(dd|ymYfTy@VJ;!tSOU>`-)fH78=7x!*k6i46sav$LUewZSot^d^ zd+_Hpdsn6v8YBHj@iYOfTbm!3)fltS^?p*xO!guN6tURe`-&&Tgt>v|Lk)_bt4%Vz z(_U%~%+4^Xr>C5gKHB(CS;zRg+9SB3_M;7q7uL@hUQeS+5g8TxwzXZGM@u@s%g%{U zDVA~lhQf!v>u*~}XH(U|a;kgMf>q7fOiqi*8uNv$`>4A`xSmyyBCTZ?zN7Ax$O`So`)EFpgdtTX}$&<)7y<= zH-X>a50&4z_j|q9!~oA_D#&J=*=^^fPuasY%#=xSD;YiHZdbq8;2dwak=DZO+0kzxoW18N7oMsr zHko2>C2J3nm>k|ydL}yfPJ&q7Jh128)754;#w@TmIOV&^S#!&y2HqQExT0)w_}nMu zjyfOWv^8Y?+RQPSv4S`~LSf%6_!_FKXA$Hy0{I97!hkR!3)AqxIOE7bE^LrV=$oEO4HJ*P9g ztlE3}1WnKxKh@rv*z8+3Z*=Cg=heTFJ>U1id$eb;wMBRoFqy`6`4 zyUNkXsxTl72m``^Fdz&J$w2(yJP+wjY#($6K0BZXd@>j3dQqUHK1a~~W4rAf^P)3u zGBl_N8}&^r?3eDa*bIMvGaZ>i_+m-^Z=v z{LpcTE^xv~c0ZDc;IK2$^)ASXzfTij>Q#roxxYKkw=1)}85sWk`d;1ybVk?yeXFnM zZnYg3W4n0Jvy}R#w6(dDn)+y}-{x7+_IplKY<=qU`Oz*9`oy(=wsL&yc2A!>zWl%W z<;-B7-}>DAJJ@6X{_F3|zWu{=ulC1bAC~xcjNGel*qh7G%|2Kzw=wK#%6-#n*?V1i zHsnydIWR~}R`*Tvi?7dWAM>b@=H<#f9%m5DX^sYQcc6@>?zrbYoHAv*2h)epL?013 zShPug4HM62@N5{vJy{(J-(G|-evg|)&V{(bc?5d~f;yPGKd0k(%;2blxwIVG5$CMU zn|*igIV7>{KH#76wLuu$%0YtlK8u>q;p|N?>{os@!BnQ(_V1s{Y|5H2APfit!hkR! z3?Kuenr&8W)x|fO5kSFbh#y0`m4$}*+W@}Nde``-(cwz^L;iVm8&374ZPZy2e05k# z>j-~oZtASeGk<00t6RTiHtMaJdxZQA+1JCvYYmCZ+U9-Nky;x=j_M%cb%sP`ZS%g% zq;_xlsQw#YXvf`IhJ;@Wt)=Ju{yI{!Sw}b2p}p08xU+mdf$~hrerie~06R^M(}e0_8{tNv8sTPRFeeC0N0jjsx4F8G!bH1>^e z8B7Cx4?=Xmgz+W*_8Z@F!G~YHI5QuMi$*+weey@#5rgP4g%8&Vndwmye^U5RvuXWy z!51Slk`%sBZqTNz7c%*BT*P4TVx=JYI$CtUG2uY%v! zAZ{T(gV@>$`RjtuS~Vjd-714_jp5I?(kDKb%@7;TWA+4}%b7b4`NOE?&EIhNfc^f# zONqmfztseP@eSkGN4*;`++*g1h3o6$TjNdlBIR(A41&8a#ow&(ao_E@`sjry#|ZIL z-8-9#A&0N7EVjl=s&SD)L>v=uS9K!ujFv4Tu}) zT+D;N7#&K?hw`7Vj^oq%X<8pm;w$)Uu2X#qe