···11SECTION "DungeonVariables", WRAM0
2233-dungeon_grid:: ds 512
44-entrance_id:: db
55-current_room:: db
66-current_width:: db
77-current_height:: db
88-generated_cells:: ds 512
33+wDungeonGrid:: ds 512
44+wEntrance:: db
55+wCurrentRoom:: db
66+wCurrentWidth:: db
77+wCurrentHeight:: db
88+wGeneratedCells:: ds 512
99+wDungeonArea:: db
1010+wTwoThirdsArea:: db
1111+wPotentialDoors:: db
9121013SECTION "DungeonCode", ROM0
11141212-BIT_USED_ROOM:: db $01
1313-BIT_ENTRANCE:: db $02
1414-BIT_DOOR_NORTH:: db $04
1515-BIT_DOOR_EAST:: db $08
1616-BIT_DOOR_SOUTH:: db $10
1717-BIT_DOOR_WEST:: db $20
1818-BIT_STAIR_BELOW:: db $40
1919-BIT_STAIR_UP:: db $80
1515+INCLUDE "macros/dungeon.inc"
1616+1717+BIT_USED_ROOM:: db %00000001
1818+BIT_ENTRANCE:: db %00000010
1919+BIT_DOOR_NORTH:: db %00000100
2020+BIT_DOOR_EAST:: db %00001000
2121+BIT_DOOR_SOUTH:: db %00010000
2222+BIT_DOOR_WEST:: db %00100000
2323+BIT_STAIR_BELOW:: db %01000000
2424+BIT_STAIR_UP:: db %10000000
2025MAX_ROOMS:: dw 512
2121-NEIGHBORS:: db %00111100
2626+NEIGHBORS:: db %00111100
22272328; Params:
2429; Starting Width: B
2530; Starting Height: C
3131+; Dungeon Area: D
3232+; Two Thirds Dungeon Area: E
2633InitDungeon::
3434+ ld a, b ; wCurrentWidth = REG_B
3535+ ld [wCurrentWidth], a
3636+ ld a, c ; wCurrentHeight = REG_C
3737+ ld [wCurrentHeight], a
3838+ ld a, d ; wDungeonArea = REG_D
3939+ ld [wDungeonArea], a
4040+ ld a, e ; wTwoThirdsArea = REG_E
4141+ ld [wTwoThirdsArea], a
4242+ ret
4343+4444+GenerateDungeon::
4545+ ; REG_B = generated_cells_number
4646+ ; REG_C = i
4747+ ld b, 0 ; REG_B = 0
4848+ ld c, 0 ; REG_C = 0
4949+.LoopCheck
5050+ ld a, [wDungeonArea] ; IF REG_B >= wDungeonArea
5151+ ld e, a
2752 ld a, b
2828- ld [current_width], a
2929- ld a, c
3030- ld [current_height], a
5353+ cp e
5454+ jp nc, .LoopSkip ; break
5555+ jp z, .LoopSkip
5656+ ld a, c ; IF REG_C == 0
5757+ cp 0
5858+ jp z, .LoopBody ; proceed to loop
5959+ cp b ; IF REG_C >= REG_B
6060+ jp nc, .LoopSkip ; break
6161+ jp z, .LoopSkip
6262+.LoopBody
6363+ ld a, c ; IF REG_C == 0
6464+ cp 0
6565+ jp nz, .LoopBody2
6666+ ld a, b ; AND REG_B == 0
6767+ cp 0
6868+ jp nz, .LoopBody2
6969+ ld d, b ; wEntrance = rand_range(0, wDungeonArea)
7070+ ld e, c
7171+ call rand
7272+ ld a, b
7373+ ld hl, wDungeonArea
7474+.LoopBodyLoop
7575+ cp [hl]
7676+ jp c, .LoopBodyLoopSkip
7777+ sub [hl]
7878+ jp .LoopBodyLoop
7979+.LoopBodyLoopSkip
8080+ ld [wEntrance], a
8181+ ld b, d
8282+ ld c, e
8383+ ld hl, wGeneratedCells ; wGeneratedCells[0] = wEntrance
8484+ ld a, l
8585+ add b
8686+ ld l, a
8787+ ld a, [wEntrance]
8888+ ld [hl], a
8989+ ld hl, wDungeonGrid ; wDungeonGrid[wEntrance] = BIT_ENTRANCE | BIT_USED_ROOM
9090+ ld e, a
9191+ ld a, l
9292+ add e
9393+ ld l, a
9494+ ld [hl], $03
9595+ ld b, 1 ; REG_B = 1
9696+.LoopBody2
9797+ call GenerateRoom ; generate_room(wDungeonGrid, REG_B, REG_C, wGeneratedCells)
9898+ ld hl, wGeneratedCells ; IF wDungeonGrid[wGeneratedCells[REG_C]] IS_NOT_USED
9999+ ld a, l
100100+ add c
101101+ ld l, a
102102+ ld e, [hl]
103103+ ld hl, wDungeonGrid
104104+ ld a, l
105105+ add e
106106+ ld l, a
107107+ ld a, [hl]
108108+ ld hl, BIT_USED_ROOM
109109+ and [hl]
110110+ jp nz, .LoopBody3
111111+ ld hl, wGeneratedCells ; SET USED_BIT IN wDungeonGrid[wGeneratedCells[REG_C]]
112112+ ld a, l
113113+ add c
114114+ ld l, a
115115+ ld e, [hl]
116116+ ld hl, wDungeonGrid
117117+ ld a, l
118118+ add e
119119+ ld l, a
120120+ ld a, [hl]
121121+ set 7, a
122122+ ld [hl], a
123123+.LoopBody3
124124+ ld a, c ; IF REG_C == REG_B - 1
125125+ ld e, b
126126+ dec e
127127+ cp e
128128+ jp nz, .LoopBody4
129129+ ld a, b
130130+ ld hl, wTwoThirdsArea ; AND REG_B < wTwoThirdsArea
131131+ cp [hl]
132132+ jp nc, .LoopBody4
133133+ jp z, .LoopBody4
134134+ ld c, -1 ; REG_C = -1
135135+.LoopBody4
136136+ inc c ; REG_C += 1
137137+ jp .LoopCheck ; LOOP
138138+.LoopSkip
139139+ ret
140140+141141+GenerateRoom::
142142+ ; REG_B = queue_size => cell_index
143143+ ; REG_C = cell_index_queue => neighbor_room
144144+ ; REG_D = door
145145+ ; REG_E = opposite_door
146146+ ; cells_queue = wGeneratedCells
147147+ ld d, b ; REG_D = rand_range(0, NEIGHBORS)
148148+ ld e, c
149149+ call rand
150150+ ld a, b
151151+ ld hl, NEIGHBORS
152152+.Loop1
153153+ cp [hl]
154154+ jp c, .Loop1Skip
155155+ sub [hl]
156156+ jp .Loop1
157157+.Loop1Skip
158158+ ld [wPotentialDoors], a
159159+ ld b, d
160160+ ld c, e
161161+ push bc
162162+ ld hl, wGeneratedCells ; REG_B = wGeneratedCells[REG_C]
163163+ ld a, l
164164+ add c
165165+ ld l, a
166166+ ld b, [hl]
167167+ ld d, 1
168168+.LoopCheck
169169+ ld a, d ; IF REG_D > NEIGHBORS
170170+ ld hl, NEIGHBORS
171171+ cp [hl]
172172+ jp nc, .LoopSkip ; BREAK
173173+ jp nz, .LoopSkip
174174+ and [hl] ; IF (REG_D & NEIGHBORS) != REG_D
175175+ cp d
176176+ jp nz, .LoopContinue ; CONTINUE
177177+ ld hl, wDungeonGrid ; IF wDungeonGrid[REG_B] & REG_D
178178+ ld a, l
179179+ add b
180180+ ld l, a
181181+ ld a, [hl]
182182+ and d
183183+ cp 0
184184+ jp nz, .LoopContinue ; CONTINUE
185185+ call GetNeighborRoomIndex ; REG_C = get_neighbor_room_index(wDungeonGrid, REG_B, REG_D)
186186+ ld a, c ; IF ! ~REG_C
187187+ cpl
188188+ cp 0
189189+ jp z, .LoopContinue ; CONTINUE
190190+ ld hl, wDungeonGrid ; IF wDungeonGrid[REG_C] & BIT_USED_ROOM
191191+ ld a, l
192192+ add c
193193+ ld l, a
194194+ ld a, [hl]
195195+ and $01
196196+ jp nz, .LoopContinue ; CONTINUE
197197+ call GetOppositeDirectionBit ; REG_E = get_opposite_direction_bit(REG_D)
198198+ ld a, [wPotentialDoors] ; IF (REG_D & wPotentialDoors) == REG_D
199199+ and d
200200+ cp d
201201+ jp nz, .LoopBody2
202202+ ld hl, wDungeonGrid ; wDungeonGrid[REG_B] |= REG_D
203203+ ld a, l
204204+ add b
205205+ ld l, a
206206+ ld a, [hl]
207207+ or d
208208+ ld [hl], a
209209+ ld hl, wDungeonGrid ; wDungeonGrid[REG_C] |= REG_E
210210+ ld a, l
211211+ add c
212212+ ld l, a
213213+ ld a, [hl]
214214+ or e
215215+ ld [hl], a
216216+.LoopBody2
217217+ ld hl, wDungeonGrid ; IF wDungeonGrid[REG_C] == REG_E
218218+ ld a, l
219219+ add c
220220+ ld l, a
221221+ ld a, [hl]
222222+ cp e
223223+ jp nz, .LoopContinue
224224+ pop hl ; wGeneratedCells[OLD_REG_B] = REG_C
225225+ push de
226226+ ld d, h
227227+ ld e, l
228228+ ld hl, wGeneratedCells
229229+ ld a, l
230230+ add d
231231+ ld l, a
232232+ ld [hl], c
233233+ inc d ; OLD_REG_B += 1
234234+ ld h, d
235235+ ld l, e
236236+ pop de
237237+ push hl
238238+.LoopContinue
239239+ rlc d ; REG_D <= 1
240240+ jp .LoopCheck ; LOOP
241241+.LoopSkip
242242+ pop bc
243243+ ret
244244+245245+GetNeighborRoomIndex::
246246+ ; REG_B = current_room
247247+ ; REG_C = return val
248248+ ; REG_D = direction
249249+250250+GetOppositeDirectionBit::
251251+ ; REG_D = door
252252+ ; REG_E = return val
253253+ ld a, d
254254+;BIT_DOOR_NORTH:: db %00000100
255255+;BIT_DOOR_EAST:: db %00001000
256256+;BIT_DOOR_SOUTH:: db %00010000
257257+;BIT_DOOR_WEST:: db %00100000
258258+ cp %00000100
259259+ jp nz, .Check1
260260+ ld e, %00010000
261261+ ret
262262+.Check1
263263+ cp %00001000
264264+ jp nz, .Check2
265265+ ld e, %00100000
266266+ ret
267267+.Check2
268268+ cp %00010000
269269+ jp nz, .Check3
270270+ ld e, %00000100
271271+ ret
272272+.Check3
273273+ cp %00100000
274274+ jp nz, .Check4
275275+ ld e, %00001000
276276+ ret
277277+.Check4
278278+ ld e, -1
31279 ret
···33randstate:: ds 4
4455SECTION "Math", ROM0
66+67;; From: https://github.com/pinobatch/libbet/blob/master/src/rand.z80#L34-L54
78; Generates a pseudorandom 16-bit integer in BC
89; using the LCG formula from cc65 rand():
···4243 ld [hl],c
4344 ret
44454545-; HL = DE * A
4646-Mul8::
4646+; HL = D * E
4747+Multiply::
4748 ld hl, 0
4848- ld b, 8
4949-.Loop:
5050- rrca
5151- jp nc, Mul8.Skip
5252- add hl, de
5353-.Skip:
5454- sla e
5555- rl d
5656- jp nz, Mul8.Loop
5757- ret
5858-5959-; A = HL % C
6060-; HL = HL / C
6161-Mod8::
6262- ld b, 16
4949+ ld a, d
5050+ or a
5151+ ret z
5252+ ld b, d
5353+ ld d, h
6354.Loop
6464- xor a
6565- add hl, hl
6666- rla
6767- cp c
6868- jp c, Mod8.Exit
6969- inc l
7070- sub c
7171- jr nz, Mod8.Loop
7272-.Exit
5555+ add hl, de
5656+ dec b
5757+ jp nz, .Loop
7358 ret