Core class. Necessary for all the examples.
TDungeon.bmx:
Maze Example 1
test1.bmx:
Maze Example 2
test2.bmx:
Dungeon Example 1
test3.bmx:
TDungeon.bmx:
Rem TDungeon V0.1 December 2006 PURPOSE A simple class for generating 'perfect' mazes and 'imperfect' dungeons TEST SYSTEMS Athlon 64 3200+, 2GB DDR400, ATI Radeon X800 GT 256MB GDDR3 Intel Centrino 1600, 512MB DDR2, ATI Radeon Mobility X700 128MB Windows XP Pro SP2 BlitzMax V1.24 MINIMUM REQUIREMENTS BlitzMax 1.24 Windows XP (Linux and MacOS untested) VERSION CHANGES 0.1 * Initial release CONSTANTS AREACLEAR_FULL AREACLEAR_PERIMETER AREATYPE_VOID AREATYPE_PILLARS AREATYPE_WALLED ENTRY_INCLUDECORNERS ENTRY_EXCLUDECORNERS METHODS AND FUNCTIONS: generate checkNeighbour createArea clearCell makeAreas getWallGrid getAreaGrid NOTES: Initially, all generated dungeons are 'perfect' mazes (that is, every cell in the maze is reachable by every other cell). To create a more interesting dungeon, 'areas' are added to the maze. An area is a space that may be blank (void), or an empty 'room' with a number of 'entries'. Clever use of areas, alone or in combinations, can offer interesting results. See the relevent method and the associated examples for more information. End Rem SuperStrict Const AREACLEAR_FULL:Int = 0 Const AREACLEAR_PERIMETER:Int = 1 Const AREATYPE_VOID:Int = 0 Const AREATYPE_PILLARS:Int = 1 Const AREATYPE_WALLED: Int = 2 Const ENTRY_INCLUDECORNERS:Int = 0 Const ENTRY_EXCLUDECORNERS:Int = 1 Type TDungeon Field SizeX:Int Field SizeZ:Int Field Dungeon:TDungeonCell[,] Method generate(seed:Int = 0, szx:Int = 16, szz:Int = 16) Rem Creates a 'perfect' maze. seed: random seed. Use Millisecs() to generate a different result every time. szx: number of grid columns. Minimum 16. szz: number of grid rows. Minimum 16. End Rem If szx < 1 Then SizeX = 16 Else SizeX = szx If szz < 1 Then SizeZ = 16 Else SizeZ = szz Dungeon = New TDungeonCell[SizeX, SizeZ] For Local x:Int = 0 To SizeX - 1 For Local z:Int = 0 To SizeZ - 1 Dungeon[x, z] = New TDungeonCell Dungeon[x, z].X = x Dungeon[x, z].Z = z Next Next SeedRnd seed Local totalcells:Int = SizeX * SizeZ Local cellstack:TDungeonCell[] cellstack = cellstack[..cellstack.length + 1] cellstack[cellstack.length - 1] = Dungeon[Rand(0, SizeX - 1), Rand(0, SizeZ - 1)] Local currentcell:TDungeonCell = cellstack[cellstack.length - 1] Local visitedcells:Int = 1 Local x:Int = currentcell.X Local z:Int = currentcell.Z While visitedcells < totalcells And (Not KeyHit(KEY_ESCAPE)) Local i:Int = -1 Local neighbors:TDungeonCell[4] Local neighborsdir:Int[4] If x > 0 Then checkNeighbour(Dungeon[x - 1, z], 2, i, neighbors, neighborsdir) If x < (SizeX - 1) Then checkNeighbour(Dungeon[x + 1, z], 3, i, neighbors, neighborsdir) If z > 0 Then checkNeighbour(Dungeon[x, z - 1], 0, i, neighbors, neighborsdir) If z < (SizeZ - 1) Then checkNeighbour(Dungeon[x, z + 1], 1, i, neighbors, neighborsdir) If (i > -1) Local n:Int = Rand(0,i) Select neighborsdir[n] Case 0 currentcell.WallN = False neighbors[n].WallS = False Case 1 currentcell.WallS = False neighbors[n].WallN = False Case 2 currentcell.WallW = False neighbors[n].WallE = False Case 3 currentcell.WallE = False neighbors[n].WallW = False End Select cellstack = cellstack[..cellstack.length + 1] cellstack[cellstack.length - 1] = neighbors[n] currentcell = cellstack[cellstack.length - 1] x = currentcell.X z = currentcell.Z visitedcells :+ 1 Else If cellstack.length > 0 currentcell = cellstack[cellstack.length - 1] x = currentcell.X z = currentcell.Z cellstack = cellstack[..cellstack.length - 1] EndIf EndIf Wend EndMethod Function checkNeighbour(cell:TDungeonCell Var, ndir:Int, i:Int Var, neighbors:TDungeonCell[] Var, neighborsdir:Int[] Var) Rem Utility Function used by the generate method. EndRem If ((cell.WallN = True) And (cell.WallS = True) And (cell.WallE = True) And (cell.WallW = True)) i :+ 1 neighbors[i] = cell neighborsdir[i] = ndir EndIf EndFunction Method createArea(id:Byte = 0, posx:Int, posz:Int, sx:Int, sz:Int, cleartyp:Int = AREACLEAR_FULL, typ:Int = AREATYPE_VOID, typdata1:Int = 0, typdata2:Int = ENTRY_INCLUDECORNERS) Rem Create an 'area' within the dungeon. id: Area id number to assign to the area' cells. Minimum 0. Maximum 255. posx: Top left column of the area. > 0 and less than the dungeon's width. posz: Top left row of the area. > 0 and less than the dungeon's height. sx: width of the area. Minimum 3. Some area types require higher minimums for full effect. sz: height of the area. Minumum 3. Some area types require higher minimums for full effect. cleartyp: Clearing type. AREACLEAR_FULL - clear the entire area of walls. AREACLEAR_PERIMETER - clear only the perimeter, preserving the inner contents. typ: Type of area to create. AREATYPE_VOID - completely blank. AREATYPE_PILLARS - pillars effect. AREATYPE_WALLED - a walled room. typdata1: if type is AREATYPE_WALLED then typdata1 = number of doors into room. Minimum 0. typdata2: if type is AREATYPE_WALLED then typdata2 = corner door placement type. ENTRY_INCLUDECORNERS or ENTRY_EXCLUDECORNERS End Rem If (posx < 0) Or (posx > (SizeX - 1)) Then Return If (posz < 0) Or (posz > (SizeZ - 1)) Then Return If (sx < 3) Or (sx >= SizeX) Then sx = 3 If (sz < 3) Or (sz >= SizeZ) Then sz = 3 'Tag relevent cells with the area id. Any existing id will be overwritten. ie a cell can only be 'classified as one room (though the visual effects will accrue) For Local x:Int = posx + 1 To (posx + sx) - 2 For Local z:Int = posz + 1 To (posz + sz) - 2 If (x >= 0) And (x < SizeX) And (z >= 0) And (z < SizeZ) Then Dungeon[x, z].AreaID = id Next Next If cleartyp = AREACLEAR_FULL For Local x:Int = posx To (posx + sx) - 1 For Local z:Int = posz To (posz + sz) - 1 clearCell(x, z) Next Next Else If cleartyp = AREACLEAR_PERIMETER For Local x:Int = posx To (posx + sx) - 1 For Local z:Int = posz To (posz + 1) clearCell(x, z) Next Next For Local x:Int = posx To (posx + 1) For Local z:Int = posz To (posz + sz) - 1 clearCell(x, z) Next Next For Local x:Int = (posx + sx - 2) To (posx + sx) - 1 For Local z:Int = posz To (posz + sz) - 1 clearCell(x, z) Next Next For Local x:Int = posx To (posx + sx) - 1 For Local z:Int = (posz + sz - 2) To (posz + sz) - 1 clearCell(x, z) Next Next EndIf Select typ Case AREATYPE_VOID Case AREATYPE_PILLARS If sx >= 5 And sz >= 5 'Only possible if the width and height of the area is >= 5 For Local x:Int = (posx + 1) To (posx - 1 + sx) - 1 Step 2 For Local z:Int = (posz + 1) To (posz - 1 + sz) - 1 Step 2 If (x =< (SizeX - 1)) And (z =< (SizeZ - 1)) Local cell:TDungeonCell = Dungeon[x, z] If (Not (x = 0)) Then cell.WallW = True If (Not (z = 0)) Then cell.WallN = True If (Not (x = (SizeX - 1))) Then cell.WallE = True If (Not (z = (SizeZ - 1))) Then cell.WallS = True EndIf Next Next EndIf Case AREATYPE_WALLED 'Walled room with entries. 'typdata1: number of doors 'typdata2 = 1: exclude corners Local pdcells:TDungeonCell[] 'Potential room entries 'West and East For Local z:Int = (posz + 1) To (posz + sz - 2) If (z =< (SizeZ - 1)) Local x:Int = posx + 1 If x < SizeX Local cell:TDungeonCell = Dungeon[x, z] cell.WallW = True pdcells = pdcells[..pdcells.length + 1] pdcells[pdcells.length - 1] = cell x = posx + sx - 2 If (x =< (SizeX - 1)) cell = Dungeon[x, z] cell.WallE = True pdcells = pdcells[..pdcells.length + 1] pdcells[pdcells.length - 1] = cell EndIf EndIf EndIf Next 'North and South For Local x:Int = (posx + 1) To (posx + sx - 2) If (x =< (SizeX - 1)) Local z:Int = posz + 1 If z < SizeZ Local cell:TDungeonCell = Dungeon[x, z] cell.WallN = True pdcells = pdcells[..pdcells.length + 1] pdcells[pdcells.length - 1] = cell z = posz + sz - 2 If (z =< (SizeZ - 1)) cell = Dungeon[x, z] pdcells = pdcells[..pdcells.length + 1] pdcells[pdcells.length - 1] = cell cell.WallS = True EndIf EndIf EndIf Next 'If necessary, remove corners from potential entry list If typdata2 = ENTRY_EXCLUDECORNERS Local eol:Int = False Local i:Int = 0 While (Not eol) Local remove:Int = False If pdcells If (pdcells[i].X = (posx + 1) And pdcells[i].Z = (posz + 1)) remove = True Else If (pdcells[i].X = (posx + sx - 2) And pdcells[i].Z = (posz + sz - 2)) remove = True Else If (pdcells[i].X = (posx + 1) And pdcells[i].Z = (posz + sz - 2)) remove = True Else If (pdcells[i].X = (posx + sx - 2) And pdcells[i].Z = (posz + 1)) remove = True EndIf EndIf EndIf EndIf EndIf If remove pdcells[i] = pdcells[pdcells.length - 1] pdcells = pdcells[..pdcells.length - 1] Else i :+ 1 EndIf If i > pdcells.length - 1 Then eol = True Wend EndIf 'shuffle potential room entries If (pdcells.length > 0) For Local n:Int = 1 To 100 Local i1:Int = Rand(0, pdcells.length - 1) Local i2:Int = Rand(0, pdcells.length - 1) Local cell1:TDungeonCell = pdcells[i1] Local cell2:TDungeonCell = pdcells[i2] pdcells[i1] = cell2 pdcells[i2] = cell1 Next 'create entries For Local n:Int = 0 To (typdata1 - 1) If n < pdcells.length clearCell(pdcells[n].X, pdcells[n].Z) EndIf Next EndIf EndSelect EndMethod Method clearCell(x:Int, z:Int) Rem Clear a specific cell of all walls, but presevere the dungeon's outermost edges if necessary. x: cell column. z: cell row. End Rem If (x =< (SizeX - 1)) And (z =< (SizeZ - 1)) Local cell:TDungeonCell = Dungeon[x, z] If (Not (x = 0)) Then cell.WallW = False If (Not (z = 0)) Then cell.WallN = False If (Not (x = (SizeX - 1))) Then cell.WallE = False If (Not (z = (SizeZ - 1))) Then cell.WallS = False EndIf EndMethod Method makeAreas(qty:Int = 1, maxsizex:Int = 4, maxsizez:Int = 4) Rem Create a number of areas in the dungeon at random locations and of random sizes. qty: Quantity of areas to create. Minimum 1. maxsizex: Maximum possible area width. Minimum 4. maxsizez: Maximum possible area height. Minimum 4. EndRem If qty <= 0 Then qty = 1 If maxsizex <= 3 Then maxsizex = 0.4 * SizeX If maxsizez <= 3 Then maxsizez = 0.4 * SizeZ For Local n:Int = 1 To qty createArea(n, Rand(0, SizeX - maxsizex), Rand(0, SizeZ - maxsizez), Rand(3, maxsizex), Rand(3, maxsizez), Rand(0, 1), Rand(0, 2), Rand(1, 4), Rand(0, 1)) Next EndMethod Method getWallGrid:Byte[,]() Rem Create a grid representation of the dungeon's walls. Most applications utilise such a data structure for dungeon processing. Returns: 2d array of byte values. True = wall. False = no wall. NOTE: The returned grid dimensions will be double the TDungeon sizes. NOTE2:'Double' walls are ignored. ie: North walls correspond to the South walls of the upper cell, South walls correspond to the North walls of the lower cell, East walls correspond to the West walls of the right cell, West walls correspond to the East walls of the left cell. EndRem Local arr:Byte[SizeX * 2 + 1, SizeZ * 2 + 1] For Local x:Int = 0 To SizeX - 1 Local ax:Int = x * 2 + 1 For Local z:Int = 0 To SizeZ - 1 Local az:Int = z * 2 + 1 If Dungeon[x, z].WallN = True arr[ax, az - 1] = True arr[ax - 1, az - 1] = True arr[ax + 1, az - 1] = True EndIf If Dungeon[x, z].WallS = True arr[ax, az + 1] = True arr[ax - 1, az + 1] = True arr[ax + 1, az + 1] = True EndIf If Dungeon[x, z].WallW = True arr[ax - 1, az] = True arr[ax - 1, az + 1] = True arr[ax - 1, az - 1] = True EndIf If Dungeon[x, z].WallE = True arr[ax + 1, az] = True arr[ax + 1, az - 1] = True arr[ax + 1, az + 1] = True EndIf Next Next Return arr EndMethod Method getAreaGrid:Byte[,]() Rem Create a grid representation of the dungeon's area ids. Returns: 2d array of byte values. Values = ids. NOTE: The returned grid dimensions will be double the TDungeon sizes. EndRem Local arr:Byte[SizeX * 2 + 1, SizeZ * 2 + 1] For Local x:Int = 0 To SizeX - 1 Local ax:Int = x * 2 + 1 For Local z:Int = 0 To SizeZ - 1 Local az:Int = z * 2 + 1 If Dungeon[x, z].AreaID <> 0 arr[ax, az] = Dungeon[x, z].AreaID arr[ax, az + 1] = Dungeon[x, z].AreaID arr[ax , az - 1] = Dungeon[x, z].AreaID arr[ax + 1, az] = Dungeon[x, z].AreaID arr[ax + 1, az + 1] = Dungeon[x, z].AreaID arr[ax + 1, az - 1] = Dungeon[x, z].AreaID arr[ax - 1, az] = Dungeon[x, z].AreaID arr[ax - 1, az + 1] = Dungeon[x, z].AreaID arr[ax - 1, az - 1] = Dungeon[x, z].AreaID EndIf Next Next Return arr EndMethod EndType Type TDungeonCell Rem Utility class used by TDungeon. EndRem Field WallN:Int = True Field WallS:Int = True Field WallE:Int = True Field WallW:Int = True Field X:Int Field Z:Int Field AreaID:Byte = 0 EndType
Maze Example 1
test1.bmx:
Rem TDungeon V0.1 Test #1 - Maze Example 1. MINIMUM REQUIREMENTS BlitzMax 1.24 Windows XP (Linux and MacOS untested, but should work) DEPENDENCIES TDungeon.bmx NOTES This example makes use of TDungeon's built-in TDungeonCell grid. (*) - Indicates an essential step in creating and generating the maze. A 'perfect' maze is one in which every cell can be reached by every other cell. ie, there are NO closed sections inaccesable from other sections. See TDungeon.bmx for function and method-specific documentation. End Rem ' ----- INITIALISATION ----- SuperStrict '(*) Import the TDungeon class file. Import "TDungeon.bmx" 'Set up the graphics window. AppTitle = "Maze Example 1" Graphics 800, 600 SetBlend ALPHABLEND SetAlpha 1.0 SetColor 0, 0, 0 SetClsColor 255, 255, 255 'Define some global variables to store the maze's dimensions. Global Columns:Int = 32 Global Rows:Int = 32 '(*) Define and create an instance of the TDungeon class. Global Maze:TDungeon = New TDungeon '(*) Generate a 'perfect' maze measuring Columns x Rows dimensions. Maze.generate MilliSecs(), Columns, Rows ' ----- MAIN LOOP ----- While Not KeyHit(KEY_ESCAPE) Cls 'Generate a new maze if the left mouse button is clicked. If MouseHit(1) Maze.generate MilliSecs(), Columns, Rows EndIf 'draw the maze onto the backbuffer. drawMaze 16, 5, 5 DrawText "Left click to generate a new maze.", 5, (16 * (Rows + 1)) + 5 'Flip the backbuffer for screen display. Flip 1 Delay 10 Wend End '----- FUNCTIONS ----- Function drawMaze(cell_size:Int = 8, col_offset:Int = 0, row_offset:Int = 0) 'Draw a simple representation of the maze. 'In this example, 'double' walls are ignored. 'ie: North walls correspond to the South walls of the upper cell, ' South walls correspond to the North walls of the lower cell, ' East walls correspond to the West walls of the right cell, ' West walls correspond to the East walls of the left cell. 'Iterate through every maze cell. 'sz and sx correspond to screen pixel coordinates. For Local c:Int = 0 To Columns - 1 Local sx:Int = (c * cell_size) + col_offset For Local r:Int = 0 To Rows - 1 Local sz:Int = (r * cell_size) + row_offset 'Draw an appropriate line for every wall: 'horizontal for north and south walls; vertical for east and west walls. If Maze.Dungeon[c, r].WallN = True Then DrawLine sx, sz, sx + cell_size, sz If Maze.Dungeon[c, r].WallS = True Then DrawLine sx, sz + cell_size, sx + cell_size, sz + cell_size If Maze.Dungeon[c, r].WallW = True Then DrawLine sx, sz, sx, sz + cell_size If Maze.Dungeon[c, r].WallE = True Then DrawLine sx + cell_size, sz, sx + cell_size, sz + cell_size Next Next EndFunction
Maze Example 2
test2.bmx:
Rem TDungeon V0.1 Test #2 - Maze Example 2. MINIMUM REQUIREMENTS BlitzMax 1.24 Windows XP (Linux and MacOS untested, but should work) DEPENDENCIES TDungeon.bmx NOTES This example makes use of TDungeon's getWallGrid method. (*) - Indicates an essential step in creating and generating the maze. A 'perfect' maze is one in which every cell can be reached by every other cell. ie, there are NO closed sections inaccesable from other sections. See TDungeon.bmx for function and method-specific documentation. End Rem ' ----- INITIALISATION ----- SuperStrict '(*) Import the TDungeon class file. Import "TDungeon.bmx" 'Set up the graphics window. AppTitle = "Maze Example 2" Graphics 800, 600 SetBlend ALPHABLEND SetAlpha 1.0 SetColor 0, 0, 0 SetClsColor 255, 255, 255 '(*) Define a 2d BYTE array to store our walls. 'Note that no dimension sizes are specified. Global WallGrid:Byte[,] 'Create some global variables to store the grid's dimensions. 'Again note that the sizes are not explicitely specified. 'They will be calculated later. Global Columns:Int Global Rows:Int generateWallGrid ' ----- MAIN LOOP ----- While Not KeyHit(KEY_ESCAPE) Cls 'Generate a new maze if the left mouse button is clicked. If MouseHit(1) generateWallGrid EndIf 'draw the maze onto the backbuffer. drawMaze 16, 5, 5 SetColor 0, 0, 0 DrawText "Left click to generate a new maze.", 5, (16 * (Rows + 1)) + 5 'Flip the backbuffer for screen display. Flip 1 Delay 10 Wend End '----- FUNCTIONS ----- Function generateWallGrid() 'Define some local variables to store the maze's INITIAL dimensions. Local initcols:Int = 16 Local initrows:Int = 16 '(*) Define and create an local instance of the TDungeon class. Local maze:TDungeon = New TDungeon '(*) Generate a 'perfect' maze measuring Columns x Rows dimensions. maze.generate MilliSecs(), initcols, initrows '(*) Get a True/False grid representation of the walls and assign it to our global MazeGrid variable WallGrid = maze.getWallGrid() 'Set our global Columns and Rows based on the returned grids' dimensions: 'usually 2 x our initial dimensions, but it's best to calculate it this way just in case. Local d:Int[] = WallGrid.Dimensions() Columns = d[0] Rows = d[1] 'Now that we have a grid representation of our maze we no longer need the TDungeon instance, 'so it can be deleted from memory. BlitzMax will automatically do this eventually 'but we'll force it to happen now: maze = Null GCCollect EndFunction Function drawMaze(cell_size:Int = 8, col_offset:Int = 0, row_offset:Int = 0) 'Draw a simple representation of the maze. 'Iterate through every maze cell. 'sz and sx correspond to screen pixel coordinates. For Local c:Int = 0 To Columns - 1 Local sx:Int = (c * cell_size) + col_offset For Local r:Int = 0 To Rows - 1 Local sz:Int = (r * cell_size) + row_offset 'Draw an appropriately colored rectangle for every cell: 'grey for walls; black for no wall. If WallGrid[c, r] = True Then SetColor 100, 100, 100 Else SetColor 0, 0, 0 DrawRect sx, sz, cell_size, cell_size Next Next EndFunction
Dungeon Example 1
test3.bmx:
Rem TDungeon V0.1 Test #3 - Dungeon Example 1. MINIMUM REQUIREMENTS BlitzMax 1.24 Windows XP (Linux and MacOS untested, but should work) DEPENDENCIES TDungeon.bmx NOTES This example makes use of TDungeon's built-in TDungeonCell grid. In the context of the TDungeon class, dungeons are simply modifications to a 'perfect' maze. 'Areas' are created within the maze that similate open regions and rooms. Some interesting results can be achieved by overlapping areas. See test1.bmx for the basics of maze generation. See TDungeon.bmx for function and method-specific documentation. End Rem ' ----- INITIALISATION ----- SuperStrict Import "TDungeon.bmx" AppTitle = "Dungeon Example 1" Graphics 800, 600 SetBlend ALPHABLEND SetAlpha 1.0 SetColor 0, 0, 0 SetClsColor 255, 255, 255 Global AreaTog:Int = 0 Global Columns:Int = 32 Global Rows:Int = 32 Global MyDungeon:TDungeon = New TDungeon generateMyDungeon ' ----- MAIN LOOP ----- While Not KeyHit(KEY_ESCAPE) Cls If MouseHit(1) generateMyDungeon EndIf If MouseHit(2) 'Create a new walled area (ie room) of a random size in a random location. 'See the createArea method in the TDungeon class for more information. MyDungeon.createArea(Rand(1, 255), Rand(1, Columns - 1), Rand(1, Rows - 1), Rand(4, 10), Rand(4, 10), Rand(0, 1), AREATYPE_WALLED, Rand(1, 4), ENTRY_EXCLUDECORNERS) EndIf If KeyHit(KEY_TAB) Then AreaTog :~ 1 drawDungeon 16, 5, 5 DrawText "Left click to generate a new dungeon.", 5, (16 * (Rows + 1)) + 5 DrawText "Right click to generate a new room.", 5, (16 * (Rows + 1)) + 20 + 5 DrawText "TAB toggles AreaID color.", 5, (16 * (Rows + 1)) + 40 + 5 Flip 1 Delay 10 Wend End '----- FUNCTIONS ----- Function generateMyDungeon() MyDungeon.generate MilliSecs(), Columns, Rows 'Create a number of 'areas' in random locations and of random types and sizes. 'See the makeAreas and createArea methods in the TDungeon class for more information. 'Every cell has an AreaID (0 to 255), set whenever an area is created. This value can 'be used, for example, to determine 'enemy placement, environmental effects, 'door, floor and wall types, etc. MyDungeon.makeAreas(12, 15, 15) EndFunction Function drawDungeon(cell_size:Int = 8, col_offset:Int = 0, row_offset:Int = 0) 'In this example, AreaID's <> 0 are denoted by green rectangles. If AreaTog SetColor 0, 196, 0 For Local c:Int = 0 To Columns - 1 Local sx:Int = (c * cell_size) + col_offset For Local r:Int = 0 To Rows - 1 Local sz:Int = (r * cell_size) + row_offset If MyDungeon.Dungeon[c, r].AreaID <> 0 DrawRect sx, sz, cell_size, cell_size EndIf Next Next EndIf SetColor 0, 0, 0 For Local c:Int = 0 To Columns - 1 Local sx:Int = (c * cell_size) + col_offset For Local r:Int = 0 To Rows - 1 Local sz:Int = (r * cell_size) + row_offset If MyDungeon.Dungeon[c, r].WallN = True Then DrawLine sx, sz, sx + cell_size, sz If MyDungeon.Dungeon[c, r].WallS = True Then DrawLine sx, sz + cell_size, sx + cell_size, sz + cell_size If MyDungeon.Dungeon[c, r].WallW = True Then DrawLine sx, sz, sx, sz + cell_size If MyDungeon.Dungeon[c, r].WallE = True Then DrawLine sx + cell_size, sz, sx + cell_size, sz + cell_size Next Next EndFunction