/*-----------------------------------------------------------------------** ** Diablo ** ** General Dungeon file ** ** (C)1995 Condor, Inc. All rights reserved. ** **-----------------------------------------------------------------------** ** $Header: /Diablo/GENDUNG.CPP 1 1/22/97 2:06p Dgartner $ **-----------------------------------------------------------------------** ** ** File Routines ** FillDungeonInfo ** DRLG ** MakeDungeonLayout **-----------------------------------------------------------------------*/ #include "diablo.h" #pragma hdrstop #include "sound.h" #include "gendung.h" #include "engine.h" #include "lighting.h" #include "palette.h" #include "items.h" #include "player.h" #include "monster.h" #include "objects.h" #include "missiles.h" #include "spells.h" /*-----------------------------------------------------------------------** ** Global variables **-----------------------------------------------------------------------*/ byte dungeon[MDMAXX][MDMAXY]; byte pdungeon[MDMAXX][MDMAXY]; byte dflags[MDMAXX][MDMAXY]; int setpc_x, setpc_y, setpc_w, setpc_h; // Where the important set piece of a level is byte *pSetPiece; BOOL setloadflag; BYTE *pSpecialCels; BYTE *pMegaTiles; BYTE *pMiniTiles; extern "C" { BYTE *pDungeonCels; BYTE *pSpeedCels; long microoffset[MAXMREND][16]; byte nWTypeTable[MAXTILES+1]; } int mcount[MAXMICRO]; int mlist[MAXMICRO]; //WORD mtype[MAXMICRO]; static WORD mtype[MAXMICRO]; // resolve ambiguity with monsters JKE 7/30 int msize[MAXMICRO]; int nummicros; BYTE nBlockTable[MAXTILES+1]; BYTE nSolidTable[MAXTILES+1]; BYTE nTransTable[MAXTILES+1]; BYTE nMissileTable[MAXTILES+1]; BYTE nTrapTable[MAXTILES+1]; int dminx, dminy, dmaxx, dmaxy; int gnDifficulty; BYTE leveltype; BYTE currlevel; BYTE setlevel; BYTE setlvlnum; BYTE setlvltype; int ViewX, ViewY; int ViewDX, ViewDY; int ViewBX, ViewBY; ScrollStruct ScrollInfo; int LvlViewX, LvlViewY; int btmbx, btmby; int btmdx, btmdy; int MicroTileLen; char TransVal; BYTE TransList[256]; int dPiece[MAXDUNX][MAXDUNY]; // Tile # MICROS dMT[MAXDUNX][MAXDUNY]; // Micro Tiles MICROS dMT2[(MAXDUNX)*(MAXDUNY)]; char dTransVal[MAXDUNX][MAXDUNY]; // Transparent active value char dLight[MAXDUNX][MAXDUNY]; // Current light value char dSaveLight[MAXDUNX][MAXDUNY]; // Static light value char dFlags[MAXDUNX][MAXDUNY]; // Flags for Solid collision, etc. char dPlayer[MAXDUNX][MAXDUNY]; // Player int dMonster[MAXDUNX][MAXDUNY]; // Monster char dDead[MAXDUNX][MAXDUNY]; // Dead plr/monster char dObject[MAXDUNX][MAXDUNY]; // Objects char dItem[MAXDUNX][MAXDUNY]; // Items char dMissile[MAXDUNX][MAXDUNY]; // Missiles char dSpecial[MAXDUNX][MAXDUNY]; // Second layer of tiling int themeCount; // Theme room count THEME_LOC themeLoc[50]; // Theme room array /*-----------------------------------------------------------------------** **-----------------------------------------------------------------------*/ void FillSolidBlockTbls() { DWORD dwTiles; BYTE *pSBFile; ZeroMemory(nBlockTable,sizeof(nBlockTable)); ZeroMemory(nSolidTable,sizeof(nSolidTable)); ZeroMemory(nTransTable,sizeof(nTransTable)); ZeroMemory(nMissileTable,sizeof(nMissileTable)); ZeroMemory(nTrapTable,sizeof(nTrapTable)); switch (leveltype) { case 0: pSBFile = LoadFileInMemSig("NLevels\\TownData\\Town.SOL",&dwTiles,'SOL '); break; case 1: if (currlevel < 17) pSBFile = LoadFileInMemSig("Levels\\L1Data\\L1.SOL",&dwTiles,'SOL '); else pSBFile = LoadFileInMemSig("NLevels\\L5Data\\L5.SOL",&dwTiles,'SOL '); //JKE Attributes loaded break; case 2: pSBFile = LoadFileInMemSig("Levels\\L2Data\\L2.SOL",&dwTiles,'SOL '); break; case 3: if (currlevel < 17) pSBFile = LoadFileInMemSig("Levels\\L3Data\\L3.SOL",&dwTiles,'SOL '); else pSBFile = LoadFileInMemSig("NLevels\\L6Data\\L6.SOL",&dwTiles,'SOL '); //JKE Attributes loaded break; case 4: pSBFile = LoadFileInMemSig("Levels\\L4Data\\L4.SOL",&dwTiles,'SOL '); break; default: app_fatal("FillSolidBlockTbls"); break; } BYTE * pTmp = pSBFile; for (DWORD d = 1; d <= dwTiles; d++) { BYTE bv = *pTmp++; if ((bv & 0x01) != 0) nSolidTable[d] = TRUE; if ((bv & 0x02) != 0) nBlockTable[d] = TRUE; if ((bv & 0x04) != 0) nMissileTable[d] = TRUE; if ((bv & 0x08) != 0) nTransTable[d] = TRUE; if ((bv & 0x80) != 0) nTrapTable[d] = TRUE; nWTypeTable[d] = (bv & 0x70) >> 4; } DiabloFreePtr(pSBFile); } /*-----------------------------------------------------------------------** **-----------------------------------------------------------------------*/ static void bs_swap(int a, int b) { int v; v = mcount[a]; mcount[a] = mcount[b]; mcount[b] = v; v = mlist[a]; mlist[a] = mlist[b]; mlist[b] = v; v = mtype[a]; mtype[a] = mtype[b]; mtype[b] = v; v = msize[a]; msize[a] = msize[b]; msize[b] = v; } /*-----------------------------------------------------------------------** **-----------------------------------------------------------------------*/ static void bubblesort(int n) { int j,k,sorted; k = n; sorted = 0; while ((k > 0) && (sorted == 0)) { sorted = 1; for (j = 0; j < k; j++) { if (mcount[j] < mcount[j+1]) { bs_swap(j, j+1); sorted = 0; } } k--; } } /*-----------------------------------------------------------------------** **-----------------------------------------------------------------------*/ void PreRendMicros() { long i,j,llvls; WORD k; long nPNum; long tl, tms, total; int numrend; WORD *mt; int t, tlen; int ok2rend; for (i = 0; i < MAXMICRO; i++) { mlist[i] = i; mcount[i] = 0; mtype[i] = 0; } if (leveltype != 4) tlen = 10; else tlen = 12; for (j = 0; j < DMAXY; j++) { for (i = 0; i < DMAXX; i++) { mt = &(dMT[i][j].mt[0]); for(t = 0; t < tlen; t++) { nPNum = mt[t]; if (nPNum) { mcount[nPNum & 0xfff]++; mtype[nPNum & 0xfff] = nPNum & 0x7000; } } } } __asm { mov ebx,dword ptr [pDungeonCels] mov eax,dword ptr [ebx] mov dword ptr [tms],eax } nummicros = tms & 0xffff; for (i = 0; i < nummicros; i++) { nPNum = i; __asm { mov ebx,dword ptr [pDungeonCels] mov eax,dword ptr [nPNum] shl eax,2 add ebx,eax mov eax,dword ptr [ebx+4] // Size sub eax,dword ptr [ebx] mov dword ptr [tms],eax } msize[i] = tms & 0xffff; } msize[0] = 0; // Zero doesn't exist // On level type 4 we cycle the lava using the translation tables so it can't // be prerendered if (leveltype == 4) { for (i = 0; i < nummicros; i++) { nPNum = i; ok2rend = 1; if (mcount[i] == 0) continue; if (mtype[i] != 0x1000) { tl = msize[i]; __asm { mov ebx,dword ptr [pDungeonCels] mov eax,dword ptr [nPNum] shl eax,2 add ebx,eax mov esi,dword ptr [pDungeonCels] add esi,dword ptr [ebx] // Source xor ebx,ebx mov ecx,dword ptr [tl] // Number of bytes to translate jecxz _XSkip _XLp1: lodsb cmp al,0 je _XOk1 cmp al,32 jae _XOk1 mov dword ptr [ok2rend],ebx _XOk1: loop _XLp1 _XSkip: nop } } else { __asm { mov ebx,dword ptr [pDungeonCels] mov eax,dword ptr [nPNum] shl eax,2 add ebx,eax mov esi,dword ptr [pDungeonCels] add esi,dword ptr [ebx] // Source xor ebx,ebx mov ecx,32 _X1Lp1: push ecx mov edx,32 _X1Lp2: xor eax,eax // Load control byte lodsb or al,al js _X1J sub edx,eax mov ecx,eax _X1Lp3: lodsb cmp al,0 je _XOk2 cmp al,32 jae _XOk2 mov dword ptr [ok2rend],ebx _XOk2: loop _X1Lp3 or edx,edx jz _X1Nxt jmp _X1Lp2 _X1J: neg al // Do jump sub edx,eax jnz _X1Lp2 _X1Nxt: pop ecx loop _X1Lp1 } } if (ok2rend == 0) mcount[i] = 0; } } bubblesort(MAXMICRO-1); total = 0; numrend = 0; if (light4flag) { while (total < 1048576) { total = total + ((long)msize[numrend] << 1); numrend++; } } else { while (total < 1048576) { total = total + ((long)msize[numrend] << 4) - ((long)msize[numrend] << 1); numrend++; } } numrend--; if (numrend > MAXMREND) numrend = MAXMREND; // Pre render the most used total = 0; if (light4flag) llvls = 3; else llvls = 15; for (j = 0; j < numrend; j++) { nPNum = mlist[j]; microoffset[j][0] = nPNum; if (mtype[j] != 0x1000) { tl = msize[j]; // Pre render for each light level for (i = 1; i < llvls; i++) { microoffset[j][i] = total; __asm { mov ebx,dword ptr [pDungeonCels] mov eax,dword ptr [nPNum] shl eax,2 add ebx,eax mov esi,dword ptr [pDungeonCels] add esi,dword ptr [ebx] // Source mov edi,dword ptr [pSpeedCels] add edi,dword ptr [total] mov ebx,dword ptr [i] // Light conversion table shl ebx,8 add ebx,dword ptr [pLightTbl] mov ecx,dword ptr [tl] // Number of bytes to translate jecxz _Skip _Lp1: lodsb xlatb stosb loop _Lp1 _Skip: nop } total += tl; } } else { // Pre render for each light level for (i = 1; i < llvls; i++) { microoffset[j][i] = total; __asm { mov ebx,dword ptr [pDungeonCels] mov eax,dword ptr [nPNum] shl eax,2 add ebx,eax mov esi,dword ptr [pDungeonCels] add esi,dword ptr [ebx] // Source mov edi,dword ptr [pSpeedCels] add edi,dword ptr [total] mov ebx,dword ptr [i] // Light conversion table shl ebx,8 add ebx,dword ptr [pLightTbl] mov ecx,32 _T1Lp1: push ecx mov edx,32 _T1Lp2: xor eax,eax // Load control byte lodsb stosb or al,al js _T1J sub edx,eax mov ecx,eax _T1Lp3: lodsb xlatb stosb loop _T1Lp3 or edx,edx jz _T1Nxt jmp _T1Lp2 _T1J: neg al // Do jump sub edx,eax jnz _T1Lp2 _T1Nxt: pop ecx loop _T1Lp1 } total += msize[j]; } } } for (j = 0; j < DMAXY; j++) { for (i = 0; i < DMAXX; i++) { if (dPiece[i][j] != 0) { mt = &(dMT[i][j].mt[0]); for(t = 0; t < tlen; t++) { if (mt[t]) { for (k = 0; k < numrend; k++) { if ((mt[t] & 0xfff) == mlist[k]) { mt[t] = mtype[k] + 0x8000 + k; k = numrend; } } } } } } } } /*-----------------------------------------------------------------------** **-----------------------------------------------------------------------*/ int CalcRot(int x, int y) { int rot; if(x < DMAXX - y) rot = ((y*y+y) + ((2*y + x + 3)*x))/2; else { x = DMAXX - x - 1; y = DMAXY - y - 1; rot = (DMAXX)*(DMAXY)-(1 + ((y*y+y) + ((2*y + x + 3)*x))/2); } return rot; } /*-----------------------------------------------------------------------** * RotateMicros * * Rotates the dMT array by 45 degrees, so that when drawn to the screen, * the elements are read sequentially. Previously, DrawHTileLine had to * scan through dMT diagonally, which causes a lot of caching. **-----------------------------------------------------------------------*/ void RotateMicros() { int x,y; for(x = 0; x < DMAXX; x++) { for(y = 0; y < DMAXX; y++) { dMT2[CalcRot(x,y)] = dMT[x][y]; } } } /*-----------------------------------------------------------------------** **-----------------------------------------------------------------------*/ void SetDungeonMicros() { int wv; int i,j; WORD *mtsource; int t; WORD *mt; int tlen; if (leveltype != 4) { MicroTileLen = 10; tlen = 10; } else { MicroTileLen = 12; tlen = 16; } // Init the light values for each piece for (j = 0; j < DMAXY; j++) { for (i = 0; i < DMAXX; i++) { wv = dPiece[i][j]; mt = &(dMT[i][j].mt[0]); if (wv != 0) { wv--; if (leveltype != 4) mtsource = (WORD *)(pMiniTiles + 20*wv); else mtsource = (WORD *)(pMiniTiles + 32*wv); for(t = 0; t < tlen; t++) // MiniTiles array uses opposite y direction // hence wierd index on next line mt[t] = mtsource[(tlen-2)-(t&0xe)+(t&1)]; } else { for(t = 0; t < tlen; t++) mt[t] = 0; } } } PreRendMicros(); RotateMicros(); if (svgamode) { ViewDX = 640; ViewDY = 352; ViewBX = 10; ViewBY = 11; } else { ViewDX = 384; ViewDY = 224; ViewBX = 6; ViewBY = 7; } } /*-----------------------------------------------------------------------** **-----------------------------------------------------------------------*/ void DRLG_InitTrans() { // Init the transparent values for each piece ZeroMemory(dTransVal,sizeof(dTransVal)); ZeroMemory(TransList,sizeof(TransList)); // JKE TransVal = 1; TransVal = 1; } /*-----------------------------------------------------------------------** ** Do Transparent values on megatiles **-----------------------------------------------------------------------*/ void DRLG_MRectTrans(int x1, int y1, int x2, int y2) { int i,j; x1 = (x1 << 1) + DIRTEDGED2 + 1; y1 = (y1 << 1) + DIRTEDGED2 + 1; x2 = (x2 << 1) + DIRTEDGED2; y2 = (y2 << 1) + DIRTEDGED2; for (j = y1; j <= y2; j++) { for (i = x1; i <= x2; i++) dTransVal[i][j] = TransVal; } TransVal++; } /*-----------------------------------------------------------------------** ** Copy Transparent values on megatiles level with 4 flags for mini **-----------------------------------------------------------------------*/ void DRLG_MCopyTrans(int sx, int sy, int dx, int dy, BOOL ul, BOOL ur, BOOL ll, BOOL lr) { char v; sx = (sx << 1) + DIRTEDGED2; sy = (sy << 1) + DIRTEDGED2; v = dTransVal[sx][sy]; dx = (dx << 1) + DIRTEDGED2; dy = (dy << 1) + DIRTEDGED2; if (ul) dTransVal[dx][dy] = v; if (ur) dTransVal[dx+1][dy] = v; if (ll) dTransVal[dx][dy+1] = v; if (lr) dTransVal[dx+1][dy+1] = v; } /*-----------------------------------------------------------------------** ** Do Transparent values on minitiles **-----------------------------------------------------------------------*/ void DRLG_RectTrans(int x1, int y1, int x2, int y2) { int i,j; for (j = y1; j <= y2; j++) { for (i = x1; i <= x2; i++) dTransVal[i][j] = TransVal; } TransVal++; } /*-----------------------------------------------------------------------** ** Copy Transparent values on minitile level **-----------------------------------------------------------------------*/ void DRLG_CopyTrans(int sx, int sy, int dx, int dy) { dTransVal[dx][dy] = dTransVal[sx][sy]; } /*-----------------------------------------------------------------------** **-----------------------------------------------------------------------*/ void DRLG_ListTrans(int num, byte *List) { int i; byte x1,y1,x2,y2; for (i = 0; i < num; i++) { x1 = *List++; y1 = *List++; x2 = *List++; y2 = *List++; DRLG_RectTrans(x1, y1, x2, y2); } } /*-----------------------------------------------------------------------** **-----------------------------------------------------------------------*/ void DRLG_AreaTrans(int num, byte *List) { int i; byte x1,y1,x2,y2; for (i = 0; i < num; i++) { x1 = *List++; y1 = *List++; x2 = *List++; y2 = *List++; DRLG_RectTrans(x1, y1, x2, y2); TransVal--; } TransVal++; } /*-----------------------------------------------------------------------** ** Fuckin all problems solved with this routine **-----------------------------------------------------------------------*/ void DRLG_InitSetPC() { setpc_x = 0; setpc_y = 0; setpc_w = 0; setpc_h = 0; } /*-----------------------------------------------------------------------** ** Don't put rnd monsters, objects in set piece areas **-----------------------------------------------------------------------*/ void DRLG_SetPC() { int i,j; int x,y,w,h; w = setpc_w << 1; h = setpc_h << 1; x = (setpc_x << 1) + DIRTEDGED2; y = (setpc_y << 1) + DIRTEDGED2; for (j = 0; j < h; j++) { for (i = 0; i < w; i++) dFlags[x+i][y+j] |= BFLAG_SETPC; } } /*-----------------------------------------------------------------------** **-----------------------------------------------------------------------*/ void Make_SetPC(int x, int y, int w, int h) { int i,j; int dx, dy, dh, dw; dw = w << 1; dh = h << 1; dx = (x << 1) + DIRTEDGED2; dy = (y << 1) + DIRTEDGED2; for (j = 0; j < dh; j++) { for (i = 0; i < dw; i++) dFlags[dx+i][dy+j] |= BFLAG_SETPC; } } /*-----------------------------------------------------------------------** **-----------------------------------------------------------------------*/ void DrawDungMiniMap(unsigned char floor) /*-----------------------------------------------------------------------** ** DESCRIPTION: Draws a mini map of the dungeon and player locations. ** INPUT: floor = The floor type to look for ** RETURN: None /*-----------------------------------------------------------------------*/ { int *p; byte *d; unsigned int pSize; int pIndex, pXMega, pYMega, pX, pY; p = &plr[0]._px; d = &dungeon[0][0]; pSize = sizeof(PlayerStruct); //*NOTE* The x and y coords had to be swapped in the compares to ecx and edx // to get the proper output coordinates for the players. app_assert(gpBuffer); __asm { mov esi,dword ptr [d] mov edi,dword ptr [gpBuffer] add edi,135248 mov edx,MDMAXY _YLp: push edi mov ecx,MDMAXX _XLp: lodsb //Read byte from dungeon array //Start Search for Player coords push eax push esi push edi mov esi,dword ptr [p] //PlayerStruct._px mov edi,0 //Initialize plr array index LoopThruPlayers: lodsd //Get _px mov pX,eax //Fill in pX lodsd //Get _py mov pY,eax //Fill in pY add esi,pSize //Add sizeof(PlayerStruct) sub esi,8 //Subtract 2 dwords read cmp pX,0 //Ignore 0,0 coords jnz PNotOrigin cmp pY,0 //Ignore 0,0 coords jz PNoX PNotOrigin: mov pIndex,edi //Save plr index jmp PMiniToMega //Convert mini tiles to mega tiles PMegaFound: cmp edx,pXMega //Did we match a players x coord? jnz PNoX cmp ecx,pYMega //Did we match a players y coord? jz Player PNoX: inc edi //Increment index cmp edi,MAX_PLRS //Are we done with our for loop? jl LoopThruPlayers pop edi pop esi pop eax //End Search for Player coords cmp al,floor //Did we find a floor piece? jz NoSave //Let background show thru jmp Other //We found a wall or something Player: pop edi pop esi pop eax cmp pIndex,0 //Are we dealing with player 0? jnz Player1 mov al,240 //Set color to white jmp Save Player1: cmp pIndex,1 //Are we dealing with player 1? jnz Player2 mov al,139 //Set color to red jmp Save Player2: cmp pIndex,2 //Are we dealing with player 2? jnz Player3 mov al,154 //Set color to orange jmp Save Player3: //We are dealing with player 3 mov al,147 //Set color to yellow jmp Save Other: mov al,131 //Set color to blue Save: mov byte ptr [edi],al mov byte ptr [edi+1],al mov byte ptr [edi+768],al mov byte ptr [edi+769],al NoSave: add edi,1536 dec ecx jnz _XLp pop edi add edi,2 dec edx jnz _YLp jmp EndL2DrawDung //Start Convert player mini tiles to mega tiles PMiniToMega: push eax push edx mov eax,pX sub eax,DIRTEDGED2 shr eax,1 mov edx,MDMAXX sub edx,eax mov pXMega,edx mov eax,pY sub eax,DIRTEDGED2 shr eax,1 mov edx,MDMAXY sub edx,eax mov pYMega,edx pop edx pop eax jmp PMegaFound //End Convert player mini tiles to mega tiles EndL2DrawDung: } } /*-----------------------------------------------------------------------** **-----------------------------------------------------------------------*/ BOOL DRLG_WillThemeRoomFit(int floor, int x, int y, int minSize, int maxSize, int *width, int *height) /*-----------------------------------------------------------------------** ** DESCRIPTION: Checks if a theme room between minSize and maxSize will fit at ** (x, y). ** INPUT: floor = Floor value to look for ** x, y = Top left corner to start search from ** minSize = Min sized room to create. This will actually create a room of ** size (minSize - 2) to account for a hall, 1 megatile wide, ** around the room. ** maxSize = Max sized room to create. This will actually create a room of ** size (maxSize - 2) to account for a hall, 1 megatile wide, ** around the room. ** *width = Actual room width return value ** *height = Actual room height return value ** ** RETURN: FALSE = Could not fit a room with specified parameters ** TRUE = Room dimensions were found /*-----------------------------------------------------------------------*/ { int ii, xx, yy; int xSmallest, ySmallest; int xArray[20]; int yArray[20]; int xCount = 0; int yCount = 0; BOOL yFlag = TRUE; BOOL xFlag = TRUE; //Check to see if we are within the bounds of the dungeon[40][40] array if ((x > (MDMAXX - maxSize)) && (y > (MDMAXY - maxSize))) return FALSE; //Skip any existing theme rooms if (!SkipThemeRoom(x, y)) return FALSE; //Intialize arrays memset(xArray, 0x00, sizeof(xArray)); memset(yArray, 0x00, sizeof(yArray)); //Find the lengths of each row and column for (ii = 0; ii < maxSize; ii++) { //Find the row lengths if (xFlag) { for (xx = x; xx < (x + maxSize); xx++) { //We ran into a wall or something if (dungeon[xx][y+ii] != floor) { if (xx < minSize) xFlag = FALSE; else break; } else xCount++; } if (xFlag) { xArray[ii] = xCount; xCount = 0; } } //Find the column lengths if (yFlag) { for (yy = y; yy < (y + maxSize); yy++) { //We ran into a wall or something if (dungeon[x+ii][yy] != floor) { if (yy < minSize) yFlag = FALSE; else break; } else yCount++; } if (yFlag) { yArray[ii] = yCount; yCount = 0; } } } //Make sure we meet the minimum requirements for (ii = 0; ii < minSize; ii++) { if (xArray[ii] < minSize || yArray[ii] < minSize) return FALSE; } //Initialize xSmallest = xArray[0]; ySmallest = yArray[0]; //Find the best x and y values for (ii = 0; ii < maxSize; ii++) { if (xArray[ii] >= minSize && yArray[ii] >= minSize) { if (xArray[ii] < xSmallest) xSmallest = xArray[ii]; if (yArray[ii] < ySmallest) ySmallest = yArray[ii]; } else break; } //Set the room dimenions *width = xSmallest - 2; //Subtract 2 to acount for hall around room *height = ySmallest - 2; //Subtract 2 to acount for hall around room return TRUE; } /*-----------------------------------------------------------------------** **-----------------------------------------------------------------------*/ void DRLG_CreateThemeRoom(int themeIndex) /*-----------------------------------------------------------------------** ** DESCRIPTION: Creates themeIndex theme room in the themeLoc array. ** INPUT: themeIndex = Index into themeLoc array ** RETURN: None /*-----------------------------------------------------------------------*/ { int xx; int yy; //Add the walls for (yy = themeLoc[themeIndex].y; yy < (themeLoc[themeIndex].y + themeLoc[themeIndex].height); yy++) { for (xx = themeLoc[themeIndex].x; xx < (themeLoc[themeIndex].x + themeLoc[themeIndex].width); xx++) { if (leveltype == 2) { //TOP/BOTTOM WALLS if ((yy == themeLoc[themeIndex].y && (xx >= themeLoc[themeIndex].x && (xx <= themeLoc[themeIndex].x + themeLoc[themeIndex].width))) || ((yy == themeLoc[themeIndex].y + (themeLoc[themeIndex].height-1)) && (xx >= themeLoc[themeIndex].x && (xx <= themeLoc[themeIndex].x + themeLoc[themeIndex].width)))) dungeon[xx][yy] = 2; //HWALL_PIECE //RIGHT/LEFT WALLS else if ((xx == themeLoc[themeIndex].x && (yy >= themeLoc[themeIndex].y && (yy <= themeLoc[themeIndex].y + themeLoc[themeIndex].height))) || ((xx == themeLoc[themeIndex].x + (themeLoc[themeIndex].width-1)) && (yy >= themeLoc[themeIndex].y && (yy <= themeLoc[themeIndex].y + themeLoc[themeIndex].height)))) dungeon[xx][yy] = 1; //VWALL_PIECE //FLOOR PIECE else dungeon[xx][yy] = 3; //FLOOR_PIECE } if (leveltype == 3) { //UPPER/LOWER WALL if ((yy == themeLoc[themeIndex].y && (xx >= themeLoc[themeIndex].x && (xx <= themeLoc[themeIndex].x + themeLoc[themeIndex].width))) || ((yy == themeLoc[themeIndex].y + (themeLoc[themeIndex].height-1)) && (xx >= themeLoc[themeIndex].x && (xx <= themeLoc[themeIndex].x + themeLoc[themeIndex].width)))) dungeon[xx][yy] = 134; //WOOD_HORIZWALL //RIGHT/LEFT WALL else if ((xx == themeLoc[themeIndex].x && (yy >= themeLoc[themeIndex].y && (yy <= themeLoc[themeIndex].y + themeLoc[themeIndex].height))) || ((xx == themeLoc[themeIndex].x + (themeLoc[themeIndex].width-1)) && (yy >= themeLoc[themeIndex].y && (yy <= themeLoc[themeIndex].y + themeLoc[themeIndex].height)))) dungeon[xx][yy] = 137; //WOOD_VERTWALL //FLOOR PIECE else dungeon[xx][yy] = 7; //FLOOR } if (leveltype == 4) { //UPPER/LOWER WALL if ((yy == themeLoc[themeIndex].y && (xx >= themeLoc[themeIndex].x && (xx <= themeLoc[themeIndex].x + themeLoc[themeIndex].width))) || ((yy == themeLoc[themeIndex].y + (themeLoc[themeIndex].height-1)) && (xx >= themeLoc[themeIndex].x && (xx <= themeLoc[themeIndex].x + themeLoc[themeIndex].width)))) dungeon[xx][yy] = 2; //HWALL_PIC //RIGHT/LEFT WALL else if ((xx == themeLoc[themeIndex].x && (yy >= themeLoc[themeIndex].y && (yy <= themeLoc[themeIndex].y + themeLoc[themeIndex].height))) || ((xx == themeLoc[themeIndex].x + (themeLoc[themeIndex].width-1)) && (yy >= themeLoc[themeIndex].y && (yy <= themeLoc[themeIndex].y + themeLoc[themeIndex].height)))) dungeon[xx][yy] = 1; //VWALL_PIC //FLOOR PIECE else dungeon[xx][yy] = 6; //FLOOR_PIC } } } //Add the corners if (leveltype == 2) { dungeon[themeLoc[themeIndex].x][themeLoc[themeIndex].y] = 8; //ULWALL_PIECE dungeon[themeLoc[themeIndex].x + (themeLoc[themeIndex].width-1)][themeLoc[themeIndex].y] = 7; //URWALL_PIECE dungeon[themeLoc[themeIndex].x][themeLoc[themeIndex].y + (themeLoc[themeIndex].height-1)] = 9; //LLWALL_PIECE dungeon[themeLoc[themeIndex].x + (themeLoc[themeIndex].width-1)][themeLoc[themeIndex].y + (themeLoc[themeIndex].height-1)] = 6; //LRWALL_PIECE } if (leveltype == 3) { dungeon[themeLoc[themeIndex].x][themeLoc[themeIndex].y] = 150; //WOOD_ULCORNER dungeon[themeLoc[themeIndex].x + (themeLoc[themeIndex].width-1)][themeLoc[themeIndex].y] = 151; //WOOD_URCORNER dungeon[themeLoc[themeIndex].x][themeLoc[themeIndex].y + (themeLoc[themeIndex].height-1)] = 152; //WOOD_LLCORNER dungeon[themeLoc[themeIndex].x + (themeLoc[themeIndex].width-1)][themeLoc[themeIndex].y + (themeLoc[themeIndex].height-1)] = 138; //WOOD_LRCORNER } if (leveltype == 4) { dungeon[themeLoc[themeIndex].x][themeLoc[themeIndex].y] = 9; //ULWALL_PIC dungeon[themeLoc[themeIndex].x + (themeLoc[themeIndex].width-1)][themeLoc[themeIndex].y] = 16; //URWALL_PIC dungeon[themeLoc[themeIndex].x][themeLoc[themeIndex].y + (themeLoc[themeIndex].height-1)] = 15; //LLWALL_PIC dungeon[themeLoc[themeIndex].x + (themeLoc[themeIndex].width-1)][themeLoc[themeIndex].y + (themeLoc[themeIndex].height-1)] = 12; //LRWALL_PIC } //Add the door to the east or south wall if (leveltype == 2) { switch(random(0, 2)) { //East wall case 0 : dungeon[themeLoc[themeIndex].x + (themeLoc[themeIndex].width-1)][themeLoc[themeIndex].y + (themeLoc[themeIndex].height / 2)] = 4; //VDOOR_PIECE break; //South wall case 1 : dungeon[themeLoc[themeIndex].x + (themeLoc[themeIndex].width / 2)][themeLoc[themeIndex].y + (themeLoc[themeIndex].height-1)] = 5; //HDOOR_PIECE break; } } if (leveltype == 3) { switch(random(0, 2)) { //East wall case 0 : dungeon[themeLoc[themeIndex].x + (themeLoc[themeIndex].width-1)][themeLoc[themeIndex].y + (themeLoc[themeIndex].height / 2)] = 147; //WOOD_VERTGATE break; //South wall case 1 : dungeon[themeLoc[themeIndex].x + (themeLoc[themeIndex].width / 2)][themeLoc[themeIndex].y + (themeLoc[themeIndex].height-1)] = 146; //WOOD_HORIZGATE break; } } if (leveltype == 4) { switch(random(0, 2)) { //East wall case 0 : dungeon[themeLoc[themeIndex].x + (themeLoc[themeIndex].width-1)][(themeLoc[themeIndex].y + (themeLoc[themeIndex].height / 2))-1] = 53; //VERT RIGHT dungeon[themeLoc[themeIndex].x + (themeLoc[themeIndex].width-1)][themeLoc[themeIndex].y + (themeLoc[themeIndex].height / 2)] = 6; //FLOOR_PIC dungeon[themeLoc[themeIndex].x + (themeLoc[themeIndex].width-1)][(themeLoc[themeIndex].y + (themeLoc[themeIndex].height / 2))+1] = 52; //VERT LEFT //Add Shadows dungeon[themeLoc[themeIndex].x + (themeLoc[themeIndex].width-2)][(themeLoc[themeIndex].y + (themeLoc[themeIndex].height / 2))-1] = 54; break; //South wall case 1 : dungeon[(themeLoc[themeIndex].x + (themeLoc[themeIndex].width / 2))-1][themeLoc[themeIndex].y + (themeLoc[themeIndex].height-1)] = 57; //HORIZ LEFT dungeon[themeLoc[themeIndex].x + (themeLoc[themeIndex].width / 2)][themeLoc[themeIndex].y + (themeLoc[themeIndex].height-1)] = 6; //FLOOR_PIC dungeon[(themeLoc[themeIndex].x + (themeLoc[themeIndex].width / 2))+1][themeLoc[themeIndex].y + (themeLoc[themeIndex].height-1)] = 56; //HORIZ RIGHT //Add Shadows dungeon[themeLoc[themeIndex].x + (themeLoc[themeIndex].width / 2)][themeLoc[themeIndex].y + (themeLoc[themeIndex].height-2)] = 59; dungeon[(themeLoc[themeIndex].x + (themeLoc[themeIndex].width / 2))-1][themeLoc[themeIndex].y + (themeLoc[themeIndex].height-2)] = 58; break; } } } /*-----------------------------------------------------------------------** **-----------------------------------------------------------------------*/ void DRLG_PlaceThemeRooms(int minSize, int maxSize, int floor, int freq, BOOL rndSize) /*-----------------------------------------------------------------------** ** DESCRIPTION: Places theme rooms in dungeon types 2,3 & 4. ** INPUT: minSize = The minimum sized room to create ** maxSize = The maximum sized room to create ** floor = The floor value to look for ** freq = The frequency to check for theme rooms. Set to 0 if you ** want to check everything. ** rndSize = If TRUE, then create rooms between max and min. If FALSE, ** then the largest theme rooms in an area will be created. ** RETURN: None /*-----------------------------------------------------------------------*/ { int i; int j; int themeW; int themeH; //Initialize themeCount = 0; memset(themeLoc, 0x00, sizeof(THEME_LOC)); //Loop thru dungeon array for (j = 0; j < MDMAXY; j++) { for (i = 0; i < MDMAXX; i++) { //Did we find a floor piece? if ((dungeon[i][j] == floor) && (!random(0, freq))) { //Check to see if theme room can fit if (DRLG_WillThemeRoomFit(floor, i, j, minSize, maxSize, &themeW, &themeH)) { //Do we want a random room size between max and min? if (rndSize) { int rv1, rv2, min, max; min = minSize - 2; max = maxSize - 2; //Get a random width rv1 = random(0, ((themeW-min)+1)); rv2 = min + random(0, rv1); if (rv2 < min || rv2 > max) themeW = min; else themeW = rv2; //Get a random height rv1 = random(0, ((themeH-min)+1)); rv2 = min + random(0, rv1); if (rv2 < min || rv2 > max) themeH = min; else themeH = rv2; } //Update the theme array themeLoc[themeCount].x = i+1; themeLoc[themeCount].y = j+1; themeLoc[themeCount].width = themeW; themeLoc[themeCount].height = themeH; //Get transparency value //Had to add special case in for L3 if (leveltype == 3) { DRLG_RectTrans( ((i+2) << 1) + DIRTEDGED2, ((j+2) << 1) + DIRTEDGED2, (((i+themeW)-1) << 1) + DIRTEDGED2+1, (((j+themeH)-1) << 1) + DIRTEDGED2+1); } else DRLG_MRectTrans(i+1, j+1, (i+themeW), (j+themeH)); themeLoc[themeCount].ttval = TransVal-1; //Add the new theme room to the dungeon DRLG_CreateThemeRoom(themeCount); //Increment theme count themeCount++; } } } } } /*-----------------------------------------------------------------------** **-----------------------------------------------------------------------*/ void DRLG_HoldThemeRooms() /*-----------------------------------------------------------------------** ** DESCRIPTION: Holds theme rooms created in dungeon types 2,3 & 4. ** INPUT: None ** RETURN: None /*-----------------------------------------------------------------------*/ { int i, x, y, xx, yy; if (themeCount > 0) { for (i = 0; i < themeCount; i++) { for (y = themeLoc[i].y; y < (themeLoc[i].y + themeLoc[i].height)-1; y++) { for (x = themeLoc[i].x; x < (themeLoc[i].x + themeLoc[i].width)-1; x++) { //Mega tiles to mini tiles xx = (x << 1) + DIRTEDGED2; yy = (y << 1) + DIRTEDGED2; dFlags[xx][yy] |= BFLAG_SETPC; dFlags[xx+1][yy] |= BFLAG_SETPC; dFlags[xx][yy+1] |= BFLAG_SETPC; dFlags[xx+1][yy+1] |= BFLAG_SETPC; } } } } } /*-----------------------------------------------------------------------** **-----------------------------------------------------------------------*/ BOOL SkipThemeRoom( int x, int y ) /*-----------------------------------------------------------------------** ** DESCRIPTION: Skips any existing theme rooms ** INPUT: None ** RETURN: TRUE = If not in a theme room ** FALSE = If in a theme room /*-----------------------------------------------------------------------*/ { int i; //Skip all L2, L3, & L4 themes rooms for (i = 0; i < themeCount; i++) { if ((x >= themeLoc[i].x-2 && x <= (themeLoc[i].x + themeLoc[i].width)+2) && (y >= themeLoc[i].y-2 && y <= (themeLoc[i].y + themeLoc[i].height)+2)) //We are inside a theme room return FALSE; } return TRUE; } /*-----------------------------------------------------------------------** **-----------------------------------------------------------------------*/ void InitLevels() { if (! leveldebug) { currlevel = 0; leveltype = 0; setlevel = FALSE; } }