mirror of
https://github.com/Pixinn/rogue-like.git
synced 2024-10-12 08:23:42 +00:00
Random level generation (post #3: https://www.xtof.info/blog/?p=1186)
This commit is contained in:
parent
7fcdb9d800
commit
eff3827d20
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,4 +1,5 @@
|
||||
.vscode/
|
||||
.DS_Store
|
||||
*.out
|
||||
*.a2
|
||||
*.o
|
||||
|
7
Makefile
7
Makefile
@ -1,7 +1,8 @@
|
||||
APPLE2_CL := $(CC65_HOME)/bin/cl65
|
||||
APPLE2_SRC := src/main.asm src/math.asm src/random.asm \
|
||||
APPLE2_SRC := src/main.asm src/math.asm src/memory.asm src/random.asm \
|
||||
src/game_loop.asm src/display.asm src/tiles.asm src/world.asm src/player.asm \
|
||||
src/debug.asm
|
||||
src/debug.asm src/builder/builder.asm src/builder/rooms.asm src/builder/maze.asm src/display_map.asm \
|
||||
src/io/title.asm src/io/textio.asm src/io/gr.asm
|
||||
APPLE2_MAP := escape.map
|
||||
APPLE2_CFLAGS := -Oirs -v -t apple2 -vm --cpu 6502
|
||||
APPLE2_OUT := bin/escape.a2
|
||||
@ -15,4 +16,4 @@ apple2: $(APPLE2_SRC)
|
||||
$(APPLE2_CL) -m $(APPLE2_MAP) -o $(APPLE2_OUT) $? $(APPLE2_CFLAGS) -C src/escape.cfg
|
||||
|
||||
clean: $(SRC)
|
||||
rm -f $(APPLE2_MAP) src/*.o src/*.s gmon.out & rm -r bin/
|
||||
rm -f $(APPLE2_MAP) src/*.o src/*.s src/builder/*.o src/builder/*.s src/io/*.s src/io/*.s gmon.out & rm -r bin/
|
||||
|
BIN
escape.dsk
BIN
escape.dsk
Binary file not shown.
@ -10,7 +10,7 @@ if (( $# != 3 )); then
|
||||
exit
|
||||
fi
|
||||
|
||||
echo " . revoving previous instance of ESCAPE form the disk"
|
||||
echo " . removing previous instance of ESCAPE form the disk"
|
||||
java -jar ${1} -d ${3} ESCAPE
|
||||
|
||||
echo " .. adding ESCAPE to the disk"
|
||||
|
@ -38,21 +38,52 @@ def fill_rect(x,y,color):
|
||||
outline = (0,0,128),
|
||||
fill = color)
|
||||
|
||||
# returns rays from (x0, y0) to (x1, y1)
|
||||
# output in rays
|
||||
def compute_rays(x0, y0, x1, y1, rays):
|
||||
ray = list(bresenham(x0, y0, x1, y1))
|
||||
# Duplicate the ray so that x and y are not incremented at the same time
|
||||
duplicated = False
|
||||
ray_x = [] # x incremented before y
|
||||
ray_y = [] # y incremented before x
|
||||
x = ray[0][0]
|
||||
y = ray[0][1]
|
||||
for tile in ray[1:]:
|
||||
if tile[0] != x and tile[1] != y:
|
||||
duplicated = True
|
||||
ray_x.append((tile[0], y))
|
||||
ray_x.append((tile[0], tile[1]))
|
||||
ray_y.append((x, tile[1]))
|
||||
ray_y.append((tile[0], tile[1]))
|
||||
else:
|
||||
ray_x.append((tile[0], tile[1]))
|
||||
ray_y.append((tile[0], tile[1]))
|
||||
x = tile[0]
|
||||
y = tile[1]
|
||||
|
||||
rays.append(ray_x)
|
||||
|
||||
if duplicated:
|
||||
rays.append(ray_y)
|
||||
|
||||
return rays
|
||||
|
||||
|
||||
|
||||
if __name__=="__main__":
|
||||
rays = []
|
||||
y = 0
|
||||
for x in range(0,SIZE_GRID-1):
|
||||
rays.append(list(bresenham(x_player,y_player,x,y)))
|
||||
rays = compute_rays(x_player,y_player,x,y, rays)
|
||||
x = SIZE_GRID-1
|
||||
for y in range(0,SIZE_GRID-1):
|
||||
rays.append(list(bresenham(x_player,y_player,x,y)))
|
||||
rays = compute_rays(x_player,y_player,x,y, rays)
|
||||
y = SIZE_GRID-1
|
||||
for x in range(SIZE_GRID-1,0,-1):
|
||||
rays.append(list(bresenham(x_player,y_player,x,y)))
|
||||
rays = compute_rays(x_player,y_player,x,y, rays)
|
||||
x = 0
|
||||
for y in range(SIZE_GRID-1,0,-1):
|
||||
rays.append(list(bresenham(x_player,y_player,x,y)))
|
||||
rays = compute_rays(x_player,y_player,x,y, rays)
|
||||
|
||||
|
||||
# create the grid
|
||||
@ -67,7 +98,7 @@ if __name__=="__main__":
|
||||
nb_cells = 0
|
||||
rgb = 0
|
||||
for ray in rays:
|
||||
for tile in ray[1:]:
|
||||
for tile in ray:
|
||||
fill_rect(tile[0], tile[1], (rgb,rgb,rgb))
|
||||
nb_cells += 1
|
||||
rgb += int(200 / len(rays))
|
||||
@ -78,8 +109,8 @@ if __name__=="__main__":
|
||||
str_ray = "; Nb rays: {}\n".format(len(rays))
|
||||
str_ray += "; A ray: length (nb_tiles), offset_from_view_in_world_low, offset_from_view_in_world_high, offset_view\nRays:\n"
|
||||
for ray in rays:
|
||||
str_ray += ".byte " + str(len(ray)-1)
|
||||
for tile in ray[1:]:
|
||||
str_ray += ".byte " + str(len(ray))
|
||||
for tile in ray:
|
||||
offset_view = tile[0] + SIZE_GRID*tile[1]
|
||||
offset_world = (tile[0] + WIDTH_WORLD*tile[1])
|
||||
offset_world_low = offset_world & 0xFF
|
||||
@ -90,4 +121,4 @@ if __name__=="__main__":
|
||||
print(str_ray)
|
||||
Im.show()
|
||||
|
||||
|
||||
|
||||
|
247
src/builder/builder.asm
Normal file
247
src/builder/builder.asm
Normal file
@ -0,0 +1,247 @@
|
||||
|
||||
; Copyright (C) 2019 Christophe Meneboeuf <christophe@xtof.info>
|
||||
;
|
||||
; This program is free software: you can redistribute it and/or modify
|
||||
; it under the terms of the GNU General Public License as published by
|
||||
; the Free Software Foundation, either version 3 of the License, or
|
||||
; (at your option) any later version.
|
||||
;
|
||||
; This program is distributed in the hope that it will be useful,
|
||||
; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
; GNU General Public License for more details.
|
||||
;
|
||||
; You should have received a copy of the GNU General Public License
|
||||
; along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
; All the dungeon builder is based on this article: http://journal.stuffwithstuff.com/2014/12/21/rooms-and-mazes/
|
||||
|
||||
.include "rooms.inc"
|
||||
.include "maze.inc"
|
||||
.include "../io/textio.inc"
|
||||
.include "../monitor.inc"
|
||||
.include "../world.inc"
|
||||
.include "../memory.inc"
|
||||
|
||||
.import World
|
||||
.import Random8
|
||||
.import Grow_Maze ; to patch
|
||||
|
||||
.export Get_Size_Maze
|
||||
.export Init_Dimensions_Maze
|
||||
.export Build_Level
|
||||
|
||||
.export Rooms
|
||||
.export WIDTH_MAZE
|
||||
.export HEIGHT_MAZE
|
||||
|
||||
.define MAX_NB_ROOMS 64 ; MAX_NB_ROOMS *MUST BE* <= 64
|
||||
|
||||
.BSS
|
||||
|
||||
; Describes a room to be built
|
||||
; typedef struct {
|
||||
; uint8_t height;
|
||||
; uint8_t width;
|
||||
; uint8_t x;
|
||||
; uint8_t y;
|
||||
; } room_t;
|
||||
.define SIZEOF_ROOM_T 4
|
||||
.align 256
|
||||
Rooms: .res SIZEOF_ROOM_T*MAX_NB_ROOMS ; MAX 1 page of data!
|
||||
|
||||
WIDTH_MAZE: .res 1
|
||||
HEIGHT_MAZE: .res 1
|
||||
|
||||
.DATA
|
||||
STR_SIZE_MAZE_1: ASCIIZ "PLEASE ENTER THE SIZE OF THE LEVEL."
|
||||
STR_SIZE_MAZE_2: ASCIIZ "A:TINY B:SMALL C:NORMAL D:BIG E:HUGE"
|
||||
STR_SIZE_MAZE_3: ASCIIZ "PLEASE ENTER A VALID CHOICE."
|
||||
|
||||
STR_ROOMS: ASCIIZ "CARVING ROOMS..."
|
||||
STR_MAZE: ASCIIZ "GROWING THE MAZE..."
|
||||
STR_DOORS: ASCIIZ "OPENING DOORS..."
|
||||
STR_DEADENDS: ASCIIZ "FILLING DEAD ENDS..."
|
||||
|
||||
.CODE
|
||||
|
||||
; @brief Asks for the size of the maze
|
||||
; Returns Width in X and Height in Y
|
||||
Get_Size_Maze:
|
||||
|
||||
; User input
|
||||
PRINT STR_SIZE_MAZE_1
|
||||
choice_size_maze:
|
||||
PRINT STR_SIZE_MAZE_2
|
||||
jsr Cin_Char
|
||||
|
||||
; switch case over the input
|
||||
tst_tiny:
|
||||
cmp #$C1
|
||||
bne tst_small
|
||||
ldx #16
|
||||
ldy #16
|
||||
rts
|
||||
tst_small:
|
||||
cmp #$C2
|
||||
bne tst_medium
|
||||
ldx #24
|
||||
ldy #24
|
||||
rts
|
||||
tst_medium:
|
||||
cmp #$C3
|
||||
bne tst_big
|
||||
ldx #32
|
||||
ldy #32
|
||||
rts
|
||||
tst_big:
|
||||
cmp #$C4
|
||||
bne tst_huge
|
||||
ldx #48
|
||||
ldy #48
|
||||
rts
|
||||
tst_huge:
|
||||
cmp #$C5
|
||||
bne bad_size
|
||||
ldx #64
|
||||
ldy #64
|
||||
rts
|
||||
bad_size:
|
||||
PRINT STR_SIZE_MAZE_3
|
||||
jmp choice_size_maze
|
||||
|
||||
|
||||
; @brief Fills border walls
|
||||
; @param type of the "wall" in A
|
||||
; destroys ZERO_2_1, ZERO_2_2
|
||||
.define ADDR_WORLD ZERO_2_1
|
||||
.macro WORLD_NEXT_LINE
|
||||
clc
|
||||
lda ADDR_WORLD
|
||||
adc #WIDTH_WORLD
|
||||
sta ADDR_WORLD
|
||||
lda ADDR_WORLD+1
|
||||
adc #0
|
||||
sta ADDR_WORLD+1
|
||||
.endmacro
|
||||
; DO NOT MESS WITH THIS FUNCTION: IT IS PATCHED!!
|
||||
.define PATCH_WIDTH_MAZE_1 0
|
||||
.define PATCH_HEIGHT_MAZE_2 0
|
||||
_build_fences:
|
||||
|
||||
ldx #<World
|
||||
stx ADDR_WORLD
|
||||
ldx #>World
|
||||
stx ADDR_WORLD+1
|
||||
ldy #PATCH_WIDTH_MAZE_1
|
||||
|
||||
loop_wall_top:
|
||||
sta (ADDR_WORLD), Y
|
||||
dey
|
||||
bne loop_wall_top
|
||||
sta (ADDR_WORLD), Y
|
||||
|
||||
ldx #PATCH_HEIGHT_MAZE_2
|
||||
loop_wall_left_right:
|
||||
pha
|
||||
WORLD_NEXT_LINE
|
||||
pla
|
||||
ldy #PATCH_WIDTH_MAZE_1
|
||||
sta (ADDR_WORLD), Y
|
||||
ldy #0
|
||||
sta (ADDR_WORLD), Y
|
||||
dex
|
||||
bne loop_wall_left_right
|
||||
|
||||
pha
|
||||
WORLD_NEXT_LINE
|
||||
pla
|
||||
ldy #PATCH_WIDTH_MAZE_1
|
||||
loop_wall_bottom:
|
||||
sta (ADDR_WORLD), Y
|
||||
dey
|
||||
bne loop_wall_bottom
|
||||
sta (ADDR_WORLD), Y
|
||||
|
||||
rts
|
||||
.undefine ADDR_WORLD
|
||||
|
||||
; @brief Sets the Maze's dimentions
|
||||
; @param width in X
|
||||
; @param height in Y
|
||||
Init_Dimensions_Maze:
|
||||
|
||||
stx WIDTH_MAZE
|
||||
; patch WIDTH_MAZE usage NO MORE PATCH: comment to be removed
|
||||
dex
|
||||
stx _build_fences + $9
|
||||
stx _build_fences + $23
|
||||
stx _build_fences + $3D
|
||||
; dex
|
||||
; dex
|
||||
; dex
|
||||
; stx Grow_Maze + $C
|
||||
; patch HEIGHT_MAZE usage NO MORE PATCH: comment to be removed
|
||||
sty HEIGHT_MAZE
|
||||
dey
|
||||
dey
|
||||
sty _build_fences + $12
|
||||
; dey
|
||||
; dey
|
||||
; sty Grow_Maze + $19
|
||||
|
||||
rts
|
||||
|
||||
; @brief Builds a whole level
|
||||
.define DST_WORLD World
|
||||
.define ADDR_TO_PATCH init_world_line + 3
|
||||
.define NB_ROOMS ZERO_8_2
|
||||
Build_Level:
|
||||
|
||||
; Filling World with ACTORS::WALL_1
|
||||
ldy #HEIGHT_WORLD
|
||||
init_world:
|
||||
ldx #0
|
||||
init_world_line:
|
||||
lda #ACTORS::WALL_1
|
||||
sta DST_WORLD, x
|
||||
inx
|
||||
cpx #WIDTH_WORLD
|
||||
bne init_world_line
|
||||
; patching DST_WORLD
|
||||
lda ADDR_TO_PATCH
|
||||
clc
|
||||
adc #WIDTH_WORLD
|
||||
sta ADDR_TO_PATCH
|
||||
lda ADDR_TO_PATCH + 1
|
||||
adc #0
|
||||
sta ADDR_TO_PATCH + 1
|
||||
dey
|
||||
bne init_world
|
||||
|
||||
PRINT STR_ROOMS
|
||||
lda #MAX_NB_ROOMS+1
|
||||
jsr Carve_Rooms
|
||||
sta NB_ROOMS
|
||||
|
||||
lda #ACTORS::FLOOR_1
|
||||
jsr _build_fences
|
||||
|
||||
PRINT STR_MAZE
|
||||
jsr Grow_Maze
|
||||
|
||||
lda #ACTORS::WALL_1
|
||||
jsr _build_fences
|
||||
|
||||
PRINT STR_DOORS
|
||||
.define PERCENT_7 #17
|
||||
ldx PERCENT_7
|
||||
lda NB_ROOMS
|
||||
jsr Connect_Rooms
|
||||
|
||||
PRINT STR_DEADENDS
|
||||
jsr Remove_Dead_Ends
|
||||
|
||||
rts
|
||||
|
19
src/builder/builder.inc
Normal file
19
src/builder/builder.inc
Normal file
@ -0,0 +1,19 @@
|
||||
; Copyright (C) 2019 Christophe Meneboeuf <christophe@xtof.info>
|
||||
;
|
||||
; This program is free software: you can redistribute it and/or modify
|
||||
; it under the terms of the GNU General Public License as published by
|
||||
; the Free Software Foundation, either version 3 of the License, or
|
||||
; (at your option) any later version.
|
||||
;
|
||||
; This program is distributed in the hope that it will be useful,
|
||||
; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
; GNU General Public License for more details.
|
||||
;
|
||||
; You should have received a copy of the GNU General Public License
|
||||
; along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
.import Get_Size_Maze
|
||||
.import Init_Dimensions_Maze
|
||||
.import Build_Level
|
||||
.import Rooms
|
534
src/builder/maze.asm
Normal file
534
src/builder/maze.asm
Normal file
@ -0,0 +1,534 @@
|
||||
; Copyright (C) 2019 Christophe Meneboeuf <christophe@xtof.info>
|
||||
;
|
||||
; This program is free software: you can redistribute it and/or modify
|
||||
; it under the terms of the GNU General Public License as published by
|
||||
; the Free Software Foundation, either version 3 of the License, or
|
||||
; (at your option) any later version.
|
||||
;
|
||||
; This program is distributed in the hope that it will be usefuELEFT,
|
||||
; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
; GNU General Public License for more details.
|
||||
;
|
||||
; You should have received a copy of the GNU General Public License
|
||||
; along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
.include "../memory.inc"
|
||||
.include "../world.inc"
|
||||
.include "../random.inc"
|
||||
.include "../math.inc"
|
||||
|
||||
|
||||
.export Grow_Maze
|
||||
.export Remove_Dead_Ends
|
||||
|
||||
.import Compute_Maze_Addr
|
||||
.import World
|
||||
.import WIDTH_MAZE
|
||||
.import HEIGHT_MAZE
|
||||
|
||||
; using HGR2 space as the stack
|
||||
; Stack contains pointers to tiles (2 byte long)
|
||||
.define STACK_ADDR $3FFE ; Will be 2 byte incremented before 1st push
|
||||
.define FALSE #0
|
||||
.define TRUE #1
|
||||
|
||||
|
||||
.define Y_TILE ZERO_2_4
|
||||
.define X_TILE ZERO_2_5
|
||||
.define PTR_STACK ZERO_4_1 ; 2 bytes
|
||||
.define PTR_NEW_TILE ZERO_4_3 ; 2 bytes
|
||||
|
||||
|
||||
; increments the stack pointer then pushes address A:X (little endian)
|
||||
; *ptr_stack = x
|
||||
; *(ptr_stack+1) = a
|
||||
; ptr_stack += 2
|
||||
.macro PUSHAX
|
||||
pha
|
||||
; increment stack pointer
|
||||
clc
|
||||
lda PTR_STACK
|
||||
adc #2
|
||||
sta PTR_STACK
|
||||
lda PTR_STACK+1
|
||||
adc #0
|
||||
sta PTR_STACK+1
|
||||
; push A:X to the stack
|
||||
pla
|
||||
ldy #1
|
||||
sta (PTR_STACK),Y
|
||||
dey
|
||||
txa
|
||||
sta (PTR_STACK),Y
|
||||
.endmacro
|
||||
|
||||
; ptr_newtile is offseted by -WIDTH_WORLD so we can access all its neighbors
|
||||
; with positive offsets using Y indirect addressing
|
||||
.macro PTR_UP_TILE
|
||||
sec
|
||||
ldy #0
|
||||
lda (PTR_STACK),Y
|
||||
sbc #(2*WIDTH_WORLD)
|
||||
sta PTR_NEW_TILE
|
||||
iny
|
||||
lda (PTR_STACK),Y
|
||||
sbc #0
|
||||
sta PTR_NEW_TILE+1
|
||||
.endmacro
|
||||
.macro PTR_LEFT_TILE
|
||||
sec
|
||||
ldy #0
|
||||
lda (PTR_STACK),Y
|
||||
sbc #(WIDTH_WORLD+1)
|
||||
sta PTR_NEW_TILE
|
||||
iny
|
||||
lda (PTR_STACK),Y
|
||||
sbc #0
|
||||
sta PTR_NEW_TILE+1
|
||||
.endmacro
|
||||
.macro PTR_RIGHT_TILE
|
||||
sec
|
||||
ldy #0
|
||||
lda (PTR_STACK),Y
|
||||
sbc #(WIDTH_WORLD-1)
|
||||
sta PTR_NEW_TILE
|
||||
iny
|
||||
lda (PTR_STACK),Y
|
||||
sbc #0
|
||||
sta PTR_NEW_TILE+1
|
||||
.endmacro
|
||||
.macro PTR_DOWN_TILE
|
||||
ldy #0
|
||||
lda (PTR_STACK),Y
|
||||
sta PTR_NEW_TILE
|
||||
iny
|
||||
lda (PTR_STACK),Y
|
||||
sta PTR_NEW_TILE+1
|
||||
.endmacro
|
||||
.macro PTR_CURR_TILE
|
||||
sec
|
||||
ldy #0
|
||||
lda (PTR_STACK),Y
|
||||
sbc #(WIDTH_WORLD)
|
||||
sta PTR_NEW_TILE
|
||||
iny
|
||||
lda (PTR_STACK),Y
|
||||
sbc #0
|
||||
sta PTR_NEW_TILE+1
|
||||
.endmacro
|
||||
|
||||
; test if the tile offseted from PTR_NEW_TILE is walkable
|
||||
.macro ISWALKABLE offset
|
||||
ldy offset
|
||||
lda (PTR_NEW_TILE),Y
|
||||
cmp #ACTORS::WALKABLE+1
|
||||
bcc cannot_carve
|
||||
.endmacro
|
||||
|
||||
|
||||
|
||||
.define OFFSET_NIL #WIDTH_WORLD
|
||||
.define OFFSET_UP #0
|
||||
.define OFFSET_RIGHT #(WIDTH_WORLD+1)
|
||||
.define OFFSET_DOWN #(2*WIDTH_WORLD)
|
||||
.define OFFSET_LEFT #(WIDTH_WORLD-1)
|
||||
|
||||
|
||||
.macro IS_TILE_WALLED
|
||||
PTR_CURR_TILE
|
||||
|
||||
ldy OFFSET_NIL
|
||||
lda (PTR_NEW_TILE),Y
|
||||
cmp #ACTORS::WALKABLE
|
||||
bcc end_loop_stack
|
||||
|
||||
ldy OFFSET_UP
|
||||
lda (PTR_NEW_TILE),Y
|
||||
cmp #ACTORS::WALKABLE
|
||||
bcc end_loop_stack
|
||||
|
||||
ldy OFFSET_RIGHT
|
||||
lda (PTR_NEW_TILE),Y
|
||||
cmp #ACTORS::WALKABLE
|
||||
bcc end_loop_stack
|
||||
|
||||
ldy OFFSET_DOWN
|
||||
lda (PTR_NEW_TILE),Y
|
||||
cmp #ACTORS::WALKABLE
|
||||
bcc end_loop_stack
|
||||
|
||||
ldy OFFSET_LEFT
|
||||
lda (PTR_NEW_TILE),Y
|
||||
cmp #ACTORS::WALKABLE
|
||||
bcc end_loop_stack
|
||||
|
||||
.endmacro
|
||||
|
||||
|
||||
; @brief Fills the empty space with a perfect maze
|
||||
.define PATCH_WIDTH_MAZE_4 0
|
||||
.define PATCH_HEIGHT_MAZE_4 0
|
||||
Grow_Maze:
|
||||
|
||||
; Groth start location
|
||||
ldx #2
|
||||
stx X_TILE
|
||||
stx Y_TILE
|
||||
|
||||
loop_grow_maze:
|
||||
|
||||
; init the stack
|
||||
lda #<STACK_ADDR
|
||||
sta PTR_STACK
|
||||
lda #>STACK_ADDR
|
||||
sta PTR_STACK+1
|
||||
|
||||
; Test if the tile is suitable
|
||||
ldy Y_TILE
|
||||
ldx X_TILE
|
||||
jsr Compute_Maze_Addr ; result addr in A:X
|
||||
|
||||
; test if the tile is walled
|
||||
PUSHAX
|
||||
IS_TILE_WALLED
|
||||
|
||||
; carve
|
||||
ldy #WIDTH_WORLD
|
||||
lda #ACTORS::FLOOR_1
|
||||
sta (PTR_NEW_TILE),Y
|
||||
|
||||
|
||||
.define IDX ZERO_2_6
|
||||
; while the stack is not empty: carve
|
||||
loop_stack:
|
||||
|
||||
jsr _random_directions
|
||||
|
||||
tax
|
||||
stx IDX
|
||||
loop_find_dir: ; find a direction suitable to carvingm
|
||||
jsr _can_carve
|
||||
cmp #1 ; cannot carve -> test other directions
|
||||
beq carve_the_tile
|
||||
lda IDX
|
||||
and #3 ; 4th direction?
|
||||
cmp #3
|
||||
beq test_stack
|
||||
inc IDX
|
||||
ldx IDX
|
||||
jmp loop_find_dir
|
||||
test_stack:
|
||||
lda PTR_STACK+1
|
||||
cmp #>(STACK_ADDR+2)
|
||||
bne unstack
|
||||
lda PTR_STACK
|
||||
cmp #<(STACK_ADDR+2)
|
||||
beq end_loop_stack ; stack is empty -> break
|
||||
unstack:
|
||||
sec
|
||||
lda PTR_STACK
|
||||
sbc #2
|
||||
sta PTR_STACK
|
||||
lda PTR_STACK+1
|
||||
sbc #0
|
||||
sta PTR_STACK+1
|
||||
jmp loop_stack
|
||||
carve_the_tile:
|
||||
; carve the tile
|
||||
ldy #0
|
||||
lda #ACTORS::FLOOR_1
|
||||
sta (PTR_NEW_TILE),Y
|
||||
jmp loop_stack
|
||||
end_loop_stack:
|
||||
|
||||
inc X_TILE
|
||||
ldx WIDTH_MAZE
|
||||
dex
|
||||
dex
|
||||
cpx X_TILE
|
||||
beq incr_y_tile
|
||||
jmp loop_grow_maze
|
||||
incr_y_tile:
|
||||
ldx #2
|
||||
stx X_TILE
|
||||
inc Y_TILE
|
||||
ldy HEIGHT_MAZE
|
||||
dey
|
||||
cpy Y_TILE
|
||||
beq end_loop_grow_maze
|
||||
jmp loop_grow_maze
|
||||
|
||||
end_loop_grow_maze:
|
||||
rts
|
||||
|
||||
|
||||
|
||||
.enum
|
||||
EUP = 0
|
||||
ERIGHT
|
||||
EDOWN
|
||||
ELEFT
|
||||
.endenum
|
||||
|
||||
; 24 direction quartets
|
||||
RandomDirection:
|
||||
.byte EUP,ERIGHT,EDOWN,ELEFT,EUP,ERIGHT,ELEFT,EDOWN,EUP,EDOWN,ERIGHT,ELEFT,EUP,EDOWN,ELEFT,ERIGHT,EUP,ELEFT,ERIGHT,EDOWN,EUP,ELEFT,EDOWN,ERIGHT
|
||||
.byte ERIGHT,EUP,EDOWN,ELEFT,ERIGHT,EUP,ELEFT,EDOWN,ERIGHT,EDOWN,EUP,ELEFT,ERIGHT,EDOWN,ELEFT,EUP,ERIGHT,ELEFT,EUP,EDOWN,ERIGHT,ELEFT,EDOWN,EUP
|
||||
.byte EDOWN,ERIGHT,EUP,ELEFT,EDOWN,ERIGHT,ELEFT,EUP,EDOWN,ELEFT,EUP,ERIGHT,EDOWN,ELEFT,ERIGHT,EUP,EDOWN,EUP,ELEFT,ERIGHT,EDOWN,EUP,ERIGHT,ELEFT
|
||||
.byte ELEFT,ERIGHT,EDOWN,EUP,ELEFT,ERIGHT,EDOWN,EUP,ELEFT,EDOWN,ERIGHT,EUP,ELEFT,EDOWN,EUP,ERIGHT,ELEFT,EUP,ERIGHT,EDOWN,ELEFT,EUP,EDOWN,ERIGHT
|
||||
|
||||
; Uses a precomputed table to quickly return an offset to one of the direction quartets
|
||||
_random_directions:
|
||||
|
||||
jsr Random8
|
||||
and #31
|
||||
ldx #24
|
||||
jsr Modulus
|
||||
asl
|
||||
asl ; offset to a direction quartet
|
||||
rts
|
||||
|
||||
; @brief Returns A=1 if the tile can be carved, A=0 otherwise.
|
||||
; some difficulties for the branches to be in range to end_can_carve.
|
||||
; thus the jsr and jmp and the breakdown of the routine
|
||||
_can_carve:
|
||||
|
||||
lda RandomDirection,X
|
||||
can_carve_up:
|
||||
cmp #EUP
|
||||
bne can_carve_right
|
||||
jmp _can_carve_up
|
||||
|
||||
can_carve_right:
|
||||
cmp #ERIGHT
|
||||
bne can_carve_down
|
||||
jmp _can_carve_right
|
||||
|
||||
can_carve_down:
|
||||
cmp #EDOWN
|
||||
bne can_carve_left
|
||||
PTR_DOWN_TILE ; ptr_newtile = down - width_world
|
||||
ISWALKABLE OFFSET_NIL ; the new tile
|
||||
ISWALKABLE OFFSET_RIGHT ; new tile's right neighbor
|
||||
ISWALKABLE OFFSET_DOWN ; new tile's bottom neighbor
|
||||
ISWALKABLE OFFSET_LEFT ; new tile's left neighbor
|
||||
jmp _save_ptr_newtile
|
||||
|
||||
can_carve_left:
|
||||
cmp #ELEFT
|
||||
bne end_can_carve
|
||||
PTR_LEFT_TILE ; ptr_newtile = left - width_world
|
||||
ISWALKABLE OFFSET_NIL ; the new tile
|
||||
ISWALKABLE OFFSET_UP ; new tile's upper neighbor
|
||||
ISWALKABLE OFFSET_DOWN ; new tile's bottom neighbor
|
||||
ISWALKABLE OFFSET_LEFT ; new tile's left neighbor
|
||||
jmp _save_ptr_newtile
|
||||
|
||||
cannot_carve:
|
||||
lda #0
|
||||
end_can_carve:
|
||||
rts
|
||||
|
||||
_can_carve_up:
|
||||
PTR_UP_TILE ; ptr_newtile = up - width_world
|
||||
ISWALKABLE OFFSET_NIL ; the new tile
|
||||
ISWALKABLE OFFSET_UP ; new tile's upper neighbor
|
||||
ISWALKABLE OFFSET_RIGHT ; new tile's right neighbor
|
||||
ISWALKABLE OFFSET_LEFT ; new tile's left neighbor
|
||||
jmp _save_ptr_newtile
|
||||
|
||||
_can_carve_right:
|
||||
PTR_RIGHT_TILE ; ptr_newtile = rigth - width_world
|
||||
ISWALKABLE OFFSET_NIL ; the new tile
|
||||
ISWALKABLE OFFSET_RIGHT ; new tile's right neighbor
|
||||
ISWALKABLE OFFSET_DOWN ; new tile's bottom neighbor
|
||||
ISWALKABLE OFFSET_UP ; new tile's upper neighbor
|
||||
; jmp _save_ptr_newtile
|
||||
|
||||
|
||||
; save new tile on the stack
|
||||
_save_ptr_newtile:
|
||||
clc
|
||||
lda PTR_NEW_TILE
|
||||
adc #WIDTH_WORLD
|
||||
sta PTR_NEW_TILE
|
||||
tax
|
||||
lda PTR_NEW_TILE+1
|
||||
adc #0
|
||||
sta PTR_NEW_TILE+1
|
||||
PUSHAX
|
||||
|
||||
;CREUSER???
|
||||
|
||||
lda #1
|
||||
jmp end_can_carve
|
||||
|
||||
.undefine Y_TILE
|
||||
.undefine X_TILE
|
||||
.undefine PTR_STACK
|
||||
.undefine PTR_NEW_TILE
|
||||
|
||||
|
||||
.define PTR_TILE ZERO_2_1 ; 2 bytes
|
||||
.define PTR_NEXT_TILE ZERO_2_3 ; 2 bytes
|
||||
.define NB_WALLS ZERO_2_5
|
||||
.define ADDR_END ZERO_4_1 ; 2 bytes
|
||||
.define HEIGHTxWIDTH WIDTH_WORLD*HEIGHT_WORLD
|
||||
; @brief Removes all the dead ends
|
||||
Remove_Dead_Ends:
|
||||
|
||||
; Compute addr_end as the preprocessor cannot handle 16bit multiplications (???)
|
||||
lda #WIDTH_WORLD
|
||||
sta FAC1
|
||||
lda #HEIGHT_WORLD
|
||||
sta FAC2
|
||||
jsr mul8
|
||||
sta ADDR_END+1
|
||||
stx ADDR_END
|
||||
lda #<World
|
||||
clc
|
||||
adc ADDR_END
|
||||
sta ADDR_END
|
||||
lda #>World
|
||||
adc ADDR_END+1
|
||||
sta ADDR_END+1
|
||||
|
||||
; starting tile: offsetted by - width_world
|
||||
lda #<(World + 1) ; &World[1][1] - width_world
|
||||
sta PTR_TILE
|
||||
lda #>(World + 1)
|
||||
sta PTR_TILE+1
|
||||
|
||||
loop_tiles:
|
||||
jsr _is_tile_dead_end
|
||||
lda NB_WALLS
|
||||
cmp #3
|
||||
bcc next_tile
|
||||
|
||||
jsr _follow_dead_end
|
||||
|
||||
next_tile:
|
||||
clc
|
||||
lda PTR_TILE
|
||||
adc #1
|
||||
sta PTR_TILE
|
||||
lda PTR_TILE+1
|
||||
adc #0
|
||||
sta PTR_TILE+1
|
||||
|
||||
; end?
|
||||
lda PTR_TILE+1
|
||||
cmp ADDR_END+1
|
||||
bne loop_tiles
|
||||
lda PTR_TILE
|
||||
cmp ADDR_END
|
||||
bne loop_tiles
|
||||
end_loop_tiles:
|
||||
|
||||
rts
|
||||
.undefine ADDR_END
|
||||
|
||||
_follow_dead_end:
|
||||
|
||||
; saving ptr_tile
|
||||
lda PTR_TILE
|
||||
pha
|
||||
lda PTR_TILE+1
|
||||
pha
|
||||
|
||||
loop_follow:
|
||||
ldy #WIDTH_WORLD
|
||||
lda #ACTORS::WALL_1
|
||||
sta (PTR_TILE), Y
|
||||
|
||||
lda PTR_NEXT_TILE
|
||||
sta PTR_TILE
|
||||
lda PTR_NEXT_TILE+1
|
||||
sta PTR_TILE+1
|
||||
|
||||
jsr _is_tile_dead_end
|
||||
lda NB_WALLS
|
||||
cmp #3
|
||||
bcs loop_follow
|
||||
|
||||
end_loop_follow:
|
||||
|
||||
; restoring ptr_tile
|
||||
pla
|
||||
sta PTR_TILE+1
|
||||
pla
|
||||
sta PTR_TILE
|
||||
|
||||
rts
|
||||
|
||||
|
||||
.define ADD_FACTOR ZERO_4_1
|
||||
; REM: PTR_TILE is already offsetted by -WIDTH_WORLD
|
||||
; for easy access to adjacent tiles by indirect indexing
|
||||
; Returns : NB_WALLS >= 3 if it is a dead end
|
||||
_is_tile_dead_end:
|
||||
|
||||
lda #0
|
||||
sta NB_WALLS
|
||||
ldy #WIDTH_WORLD
|
||||
sty ADD_FACTOR
|
||||
|
||||
; Returns if the tile is a wall
|
||||
lda #ACTORS::WALKABLE
|
||||
cmp (PTR_TILE), Y
|
||||
bcc end_tst_up_tile
|
||||
|
||||
tst_up_tile:
|
||||
ldy #0
|
||||
cmp (PTR_TILE), Y
|
||||
bcc up_non_walkable
|
||||
sty ADD_FACTOR
|
||||
bcs tst_right_tile
|
||||
up_non_walkable:
|
||||
inc NB_WALLS
|
||||
tst_right_tile:
|
||||
ldy #(WIDTH_WORLD + 1)
|
||||
cmp (PTR_TILE), Y
|
||||
bcc right_non_walkable
|
||||
sty ADD_FACTOR
|
||||
bcs tst_down_tile
|
||||
right_non_walkable:
|
||||
inc NB_WALLS
|
||||
tst_down_tile:
|
||||
ldy #(2*WIDTH_WORLD)
|
||||
cmp (PTR_TILE), Y
|
||||
bcc down_non_walkable
|
||||
sty ADD_FACTOR
|
||||
bcs tst_left_tile
|
||||
down_non_walkable:
|
||||
inc NB_WALLS
|
||||
tst_left_tile:
|
||||
ldy #(WIDTH_WORLD - 1)
|
||||
cmp (PTR_TILE), Y
|
||||
bcc left_non_walkable
|
||||
sty ADD_FACTOR
|
||||
bcs end_tests
|
||||
left_non_walkable:
|
||||
inc NB_WALLS
|
||||
|
||||
end_tests:
|
||||
; computing ptr_next_tile
|
||||
clc
|
||||
lda PTR_TILE
|
||||
adc ADD_FACTOR
|
||||
sta PTR_NEXT_TILE
|
||||
lda PTR_TILE+1
|
||||
adc #0
|
||||
sta PTR_NEXT_TILE+1
|
||||
; offseting ptr_next_tile
|
||||
sec
|
||||
lda PTR_NEXT_TILE
|
||||
sbc #WIDTH_WORLD
|
||||
sta PTR_NEXT_TILE
|
||||
lda PTR_NEXT_TILE+1
|
||||
sbc #0
|
||||
sta PTR_NEXT_TILE+1
|
||||
|
||||
end_tst_up_tile:
|
||||
rts
|
2
src/builder/maze.inc
Normal file
2
src/builder/maze.inc
Normal file
@ -0,0 +1,2 @@
|
||||
.import Grow_Maze
|
||||
.import Remove_Dead_Ends
|
664
src/builder/rooms.asm
Normal file
664
src/builder/rooms.asm
Normal file
@ -0,0 +1,664 @@
|
||||
|
||||
; Copyright (C) 2019 Christophe Meneboeuf <christophe@xtof.info>
|
||||
;
|
||||
; This program is free software: you can redistribute it and/or modify
|
||||
; it under the terms of the GNU General Public License as published by
|
||||
; the Free Software Foundation, either version 3 of the License, or
|
||||
; (at your option) any later version.
|
||||
;
|
||||
; This program is distributed in the hope that it will be useful,
|
||||
; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
; GNU General Public License for more details.
|
||||
;
|
||||
; You should have received a copy of the GNU General Public License
|
||||
; along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
.include "../memory.inc"
|
||||
.include "../random.inc"
|
||||
.include "../world.inc"
|
||||
.include "../math.inc"
|
||||
|
||||
.export Carve_Rooms
|
||||
.export Connect_Rooms
|
||||
|
||||
.import Rooms
|
||||
.import Compute_Maze_Addr
|
||||
.import World
|
||||
.import WIDTH_MAZE
|
||||
.import HEIGHT_MAZE
|
||||
|
||||
|
||||
.define TRUE #1
|
||||
.define FALSE #0
|
||||
|
||||
.BSS
|
||||
|
||||
; Configration to build rooms
|
||||
.struct Config_Room
|
||||
width_min .byte
|
||||
width_max .byte
|
||||
height_min .byte
|
||||
height_max .byte
|
||||
.endstruct
|
||||
|
||||
.CODE
|
||||
|
||||
.define NB_ATTEMPTS ZERO_2_1
|
||||
.define NB_ROOMS_OK ZERO_2_2
|
||||
.define NB_ROOMS_TO_DRAW NB_ATTEMPTS
|
||||
.define IDX_ROOMS ZERO_3
|
||||
|
||||
; @params A nb_attempts
|
||||
; @returns NB_ROOMS_OK in A
|
||||
Carve_Rooms:
|
||||
|
||||
sta NB_ATTEMPTS
|
||||
|
||||
; height_max + width_max shall be < 64
|
||||
lda #9
|
||||
sta Config_Room::height_max
|
||||
lda #3
|
||||
sta Config_Room::height_min
|
||||
lda #11
|
||||
sta Config_Room::width_max
|
||||
lda #3
|
||||
sta Config_Room::width_min
|
||||
|
||||
ldx #0
|
||||
stx NB_ROOMS_OK
|
||||
|
||||
loop_rooms:
|
||||
|
||||
dec NB_ATTEMPTS
|
||||
beq end_loop_rooms
|
||||
lda NB_ROOMS_OK ; NB_ROOMS_OK*sizeof(room_t) -> X
|
||||
asl
|
||||
asl
|
||||
tax
|
||||
|
||||
jsr _Build_Room
|
||||
|
||||
lda NB_ROOMS_OK
|
||||
jsr _Is_intersecting
|
||||
cmp TRUE ; not intersecting with another room?
|
||||
beq loop_rooms
|
||||
|
||||
inc NB_ROOMS_OK
|
||||
clc
|
||||
bcc loop_rooms
|
||||
|
||||
end_loop_rooms:
|
||||
|
||||
lda NB_ROOMS_OK
|
||||
sta NB_ROOMS_TO_DRAW
|
||||
|
||||
ldx #0
|
||||
loop_draw_rooms:
|
||||
|
||||
jsr _Draw_Room
|
||||
|
||||
inx
|
||||
inx
|
||||
inx
|
||||
inx
|
||||
|
||||
dec NB_ROOMS_TO_DRAW
|
||||
bne loop_draw_rooms
|
||||
|
||||
end_loop_draw_rooms:
|
||||
|
||||
|
||||
lda NB_ROOMS_OK
|
||||
|
||||
rts
|
||||
.undefine NB_ATTEMPTS
|
||||
.undefine NB_ROOMS_OK
|
||||
.undefine NB_ROOMS_TO_DRAW
|
||||
.undefine IDX_ROOMS
|
||||
|
||||
|
||||
.define ADDR_WORLD ZERO_2_3 ; 2 bytes
|
||||
.define NB_LINE ZERO_2_5
|
||||
.define LINE_LENGTH ZERO_2_6
|
||||
.define IDX_ROOMS ZERO_3
|
||||
_Draw_Room:
|
||||
|
||||
stx IDX_ROOMS
|
||||
|
||||
ldy Rooms+3, X ; room->y
|
||||
lda Rooms+2, X ; rooms->x
|
||||
tax
|
||||
PUSH ZERO_2_1
|
||||
PUSH ZERO_2_2
|
||||
jsr Compute_Maze_Addr
|
||||
stx ADDR_WORLD
|
||||
sta ADDR_WORLD+1
|
||||
POP ZERO_2_2
|
||||
POP ZERO_2_1
|
||||
|
||||
|
||||
ldx IDX_ROOMS
|
||||
ldy Rooms, X ; room->height
|
||||
sty NB_LINE
|
||||
lda Rooms+1, X ; room->width
|
||||
sta LINE_LENGTH
|
||||
loop_draw_line:
|
||||
lda #ACTORS::FLOOR_1
|
||||
ldy #0
|
||||
loop_draw_tile:
|
||||
sta (ADDR_WORLD), Y
|
||||
iny
|
||||
cpy LINE_LENGTH
|
||||
bne loop_draw_tile
|
||||
end_loop_draw_tile:
|
||||
clc
|
||||
lda ADDR_WORLD
|
||||
adc #WIDTH_WORLD
|
||||
sta ADDR_WORLD
|
||||
lda ADDR_WORLD+1
|
||||
adc #0
|
||||
sta ADDR_WORLD+1
|
||||
dec NB_LINE
|
||||
bne loop_draw_line
|
||||
end_loop_draw_line:
|
||||
|
||||
ldx IDX_ROOMS
|
||||
rts
|
||||
.undefine ADDR_WORLD
|
||||
.undefine NB_LINE
|
||||
.undefine LINE_LENGTH
|
||||
.undefine IDX_ROOMS
|
||||
|
||||
|
||||
.define MODULUS ZERO_2_3
|
||||
.define WIDTH_ROOM ZERO_2_5
|
||||
.define HEIGHT_ROOM ZERO_2_6
|
||||
.define OFFSET_ROOMS ZERO_5_1
|
||||
; @param X offset to the room to be built from Rooms
|
||||
; @return offset room in X
|
||||
_Build_Room:
|
||||
|
||||
stx OFFSET_ROOMS
|
||||
|
||||
; room.height = config->height_min + Random8() % (config->height_max - config->height_min - 1);
|
||||
sec
|
||||
lda Config_Room::height_max
|
||||
sbc Config_Room::height_min
|
||||
sbc #1
|
||||
sta MODULUS
|
||||
jsr Random8
|
||||
and #7
|
||||
ldx MODULUS
|
||||
jsr Modulus
|
||||
ldx OFFSET_ROOMS
|
||||
clc
|
||||
adc Config_Room::height_min
|
||||
ora #1
|
||||
sta Rooms, x ; height
|
||||
sta HEIGHT_ROOM
|
||||
inx
|
||||
stx OFFSET_ROOMS
|
||||
|
||||
; room.width = config->width_min + Random8() % (config->width_max - config->width_min - 1);
|
||||
sec
|
||||
lda Config_Room::width_max
|
||||
sbc Config_Room::width_min
|
||||
sbc #1
|
||||
sta MODULUS
|
||||
jsr Random8
|
||||
and #$F ; room's height shall be < 16
|
||||
ldx MODULUS
|
||||
jsr Modulus
|
||||
ldx OFFSET_ROOMS
|
||||
clc
|
||||
adc Config_Room::width_min
|
||||
ora #1
|
||||
sta Rooms, x ; width
|
||||
sta WIDTH_ROOM
|
||||
inx
|
||||
stx OFFSET_ROOMS
|
||||
|
||||
|
||||
; room.x = 3 + Random8() % (WIDTH_MAZE - room.width - 5);
|
||||
sec
|
||||
lda WIDTH_MAZE
|
||||
sbc WIDTH_ROOM
|
||||
sbc #5
|
||||
sta MODULUS
|
||||
jsr Random8
|
||||
and #$7F
|
||||
ldx MODULUS
|
||||
jsr Modulus
|
||||
ldx OFFSET_ROOMS
|
||||
clc
|
||||
adc #3
|
||||
ora #1
|
||||
sta Rooms, x ; x
|
||||
inx
|
||||
stx OFFSET_ROOMS
|
||||
|
||||
; room.y = 3 + Random8() % (HEIGHT_MAZE - room.height - 5);
|
||||
sec
|
||||
lda HEIGHT_MAZE
|
||||
sbc HEIGHT_ROOM
|
||||
sbc #5
|
||||
sta MODULUS
|
||||
jsr Random8
|
||||
and #$7F
|
||||
ldx MODULUS
|
||||
jsr Modulus
|
||||
ldx OFFSET_ROOMS
|
||||
clc
|
||||
adc #3
|
||||
ora #1
|
||||
sta Rooms, x ; y
|
||||
inx
|
||||
stx OFFSET_ROOMS
|
||||
|
||||
rts
|
||||
.undefine MODULUS
|
||||
.undefine WIDTH_ROOM
|
||||
.undefine HEIGHT_ROOM
|
||||
.undefine OFFSET_ROOMS
|
||||
|
||||
|
||||
; @brief test ifthe room is intersecting with other rooms
|
||||
; @param A : nb rooms already carved
|
||||
; @return 0 if no intersection, 1 otherwise
|
||||
.define NB_ROOMS ZERO_3
|
||||
.define OFFSET_Y ZERO_2_4
|
||||
.define OFFSET_X ZERO_2_5
|
||||
_Is_intersecting:
|
||||
|
||||
cmp #0
|
||||
bne compare
|
||||
; first room
|
||||
lda FALSE
|
||||
clc
|
||||
bcc end_intersecting ; branch always
|
||||
|
||||
; previous rooms were carved
|
||||
compare:
|
||||
sta NB_ROOMS
|
||||
asl ; * sizeof(room_t) to get offset to the last room randomized
|
||||
asl
|
||||
tax ; offset to new room in X
|
||||
stx OFFSET_X
|
||||
ldy #0 ; offset to carved rooms in Y
|
||||
|
||||
loop_intersecting: ; each test must be true
|
||||
sty OFFSET_Y
|
||||
clc
|
||||
lda Rooms+2, Y ; room->x
|
||||
adc Rooms+1, Y ; room->width
|
||||
cmp Rooms+2, X
|
||||
bcc false ; branch if room->x + room->width < new_room->x
|
||||
clc
|
||||
lda Rooms+2, X ; new_room->x
|
||||
adc Rooms+1, X ; new_room->width
|
||||
cmp Rooms+2, Y ; room->x
|
||||
bcc false ; branch if new_room->x + new_room->width < room->x
|
||||
clc
|
||||
lda Rooms+3, Y ; room->y
|
||||
adc Rooms, Y ; room->height
|
||||
cmp Rooms+3, X ; new_room->y
|
||||
bcc false ; branch if room->y + room->height < new_room->y
|
||||
clc
|
||||
lda Rooms+3, X ; new_room->y
|
||||
adc Rooms, X ; new_room->height
|
||||
cmp Rooms+3, Y ; room->y
|
||||
bcc false ; branch if new_room->y + new_room->height < room->y
|
||||
; all test are true: rooms are intersecting
|
||||
lda TRUE ; return value
|
||||
clc
|
||||
bcc end_intersecting
|
||||
|
||||
false:
|
||||
ldx OFFSET_X
|
||||
lda OFFSET_Y
|
||||
adc #4
|
||||
tay
|
||||
dec NB_ROOMS
|
||||
bne loop_intersecting
|
||||
|
||||
lda FALSE ; no room intersects
|
||||
|
||||
end_intersecting:
|
||||
rts
|
||||
|
||||
|
||||
; using HGR2 space as the stack
|
||||
; Stack contains pointers to the tiles encompassing a room (except the corners)
|
||||
.define STACK_ADDR $4000
|
||||
.define PTR_TILE_TOP ZERO_2_3 ; 2 bytes
|
||||
.define PTR_TILE_BOT ZERO_4_4 ; 2 bytes
|
||||
.define PTR_TILE_LEFT ZERO_2_3 ; 2 bytes
|
||||
.define PTR_TILE_RIGHT ZERO_4_4 ; 2 bytes
|
||||
.define PTR_TILE ZERO_2_1
|
||||
.define PTR_STACK ZERO_4_1 ; 2 bytes
|
||||
.define PROBABILITY_OPENING ZERO_4_3
|
||||
.define NB_DOORS ZERO_5_1
|
||||
.define NB_WALKABLE ZERO_5_2
|
||||
.define SIZE_STACK ZERO_5_3 ; 2 bytes
|
||||
.define WIDTH_ROOM ZERO_2_5
|
||||
.define HEIGHT_ROOM ZERO_2_6
|
||||
.define OFFSET_ROOMS ZERO_5_5
|
||||
|
||||
; @brief Connects the rooms to the maze's galleries
|
||||
; @param A number of rooms
|
||||
; @param X probability to make an opening in a wall tile
|
||||
; @detail One opening is made, then all remaning encompassing wall tiles
|
||||
; can be opened. Depending on the provided probability
|
||||
Connect_Rooms:
|
||||
|
||||
sta NB_ROOMS
|
||||
stx PROBABILITY_OPENING
|
||||
|
||||
lda #0
|
||||
sta OFFSET_ROOMS
|
||||
; for each room
|
||||
loop_connect_rooms:
|
||||
|
||||
; # Build a stack of encompassing tiles. Except corners
|
||||
lda #<STACK_ADDR
|
||||
sta PTR_STACK
|
||||
lda #>STACK_ADDR
|
||||
sta PTR_STACK+1
|
||||
|
||||
; ## stacking horizontal walls
|
||||
; ### init ptr_top
|
||||
ldx OFFSET_ROOMS
|
||||
inx
|
||||
inx
|
||||
lda Rooms, X ; room->x
|
||||
sta PTR_TILE_TOP
|
||||
clc
|
||||
lda #<World
|
||||
adc PTR_TILE_TOP
|
||||
sta PTR_TILE_TOP
|
||||
lda #>World
|
||||
adc #0
|
||||
sta PTR_TILE_TOP+1
|
||||
inx
|
||||
lda Rooms, X ; room->y
|
||||
tax
|
||||
dex
|
||||
stx FAC1
|
||||
lda #WIDTH_WORLD
|
||||
sta FAC2
|
||||
jsr mul8
|
||||
tay
|
||||
txa
|
||||
clc
|
||||
adc PTR_TILE_TOP
|
||||
sta PTR_TILE_TOP
|
||||
tya
|
||||
adc PTR_TILE_TOP+1
|
||||
sta PTR_TILE_TOP+1
|
||||
|
||||
; ### init ptr_bottom
|
||||
ldx OFFSET_ROOMS
|
||||
lda Rooms, X ; room->height
|
||||
sta HEIGHT_ROOM
|
||||
tax
|
||||
inx
|
||||
stx FAC1
|
||||
lda #WIDTH_WORLD
|
||||
sta FAC2
|
||||
jsr mul8
|
||||
tay
|
||||
txa
|
||||
clc
|
||||
adc PTR_TILE_TOP
|
||||
sta PTR_TILE_BOT
|
||||
tya
|
||||
adc PTR_TILE_TOP+1
|
||||
sta PTR_TILE_BOT+1
|
||||
|
||||
; ## stacking
|
||||
ldx OFFSET_ROOMS
|
||||
inx
|
||||
lda Rooms, X ; room->width
|
||||
sta WIDTH_ROOM
|
||||
; for x = 0; x < room->width; x++
|
||||
ldx #0
|
||||
loop_stack_horiz:
|
||||
ldy #0
|
||||
clc
|
||||
txa
|
||||
adc PTR_TILE_TOP
|
||||
sta (PTR_STACK), Y
|
||||
iny
|
||||
lda #0
|
||||
adc PTR_TILE_TOP+1
|
||||
sta (PTR_STACK), Y
|
||||
iny
|
||||
txa
|
||||
adc PTR_TILE_BOT
|
||||
sta (PTR_STACK), Y
|
||||
iny
|
||||
lda #0
|
||||
adc PTR_TILE_BOT+1
|
||||
sta (PTR_STACK), Y
|
||||
iny
|
||||
; incr ptr_stack
|
||||
tya
|
||||
clc
|
||||
adc PTR_STACK
|
||||
sta PTR_STACK
|
||||
lda #0
|
||||
adc PTR_STACK+1
|
||||
sta PTR_STACK+1
|
||||
; next x
|
||||
inx
|
||||
cpx WIDTH_ROOM
|
||||
bne loop_stack_horiz
|
||||
|
||||
; ## stacking vertical walls
|
||||
; ### init ptr_left
|
||||
clc
|
||||
lda #(WIDTH_WORLD-1)
|
||||
adc PTR_TILE_TOP
|
||||
sta PTR_TILE_LEFT
|
||||
lda #0
|
||||
adc PTR_TILE_TOP+1
|
||||
sta PTR_TILE_LEFT+1
|
||||
; ### init ptr_right
|
||||
clc
|
||||
lda WIDTH_ROOM
|
||||
adc #1
|
||||
adc PTR_TILE_LEFT
|
||||
sta PTR_TILE_RIGHT
|
||||
lda #0
|
||||
adc PTR_TILE_LEFT+1
|
||||
sta PTR_TILE_RIGHT+1
|
||||
; ### stacking
|
||||
; for y = 0; y < room->height; y++
|
||||
ldx #0
|
||||
loop_stack_vertical:
|
||||
ldy #1
|
||||
lda PTR_TILE_LEFT+1
|
||||
sta (PTR_STACK), Y
|
||||
dey
|
||||
lda PTR_TILE_LEFT
|
||||
sta (PTR_STACK), Y
|
||||
clc
|
||||
adc #WIDTH_WORLD
|
||||
sta PTR_TILE_LEFT
|
||||
lda PTR_TILE_LEFT+1
|
||||
adc #0
|
||||
sta PTR_TILE_LEFT+1
|
||||
iny
|
||||
iny
|
||||
iny
|
||||
lda PTR_TILE_RIGHT+1
|
||||
sta (PTR_STACK), Y
|
||||
dey
|
||||
lda PTR_TILE_RIGHT
|
||||
sta (PTR_STACK), Y
|
||||
clc
|
||||
adc #WIDTH_WORLD
|
||||
sta PTR_TILE_RIGHT
|
||||
lda PTR_TILE_RIGHT+1
|
||||
adc #0
|
||||
sta PTR_TILE_RIGHT+1
|
||||
; incr ptr_stack
|
||||
clc
|
||||
lda #4
|
||||
adc PTR_STACK
|
||||
sta PTR_STACK
|
||||
lda #0
|
||||
adc PTR_STACK+1
|
||||
sta PTR_STACK+1
|
||||
; next y
|
||||
inx
|
||||
cpx HEIGHT_ROOM
|
||||
bne loop_stack_vertical
|
||||
|
||||
; ## Compute stack's size
|
||||
; UTILISER DIRECTEMENT L ADRESSE DE FIN ET BREAKER QUAND ON L ATTEINT
|
||||
sec
|
||||
lda PTR_STACK
|
||||
sbc #<STACK_ADDR
|
||||
pha
|
||||
lda PTR_STACK+1
|
||||
sbc #>STACK_ADDR
|
||||
lsr
|
||||
sta SIZE_STACK+1
|
||||
pla
|
||||
ror
|
||||
sta SIZE_STACK
|
||||
|
||||
; # Opening the first door
|
||||
lda #0
|
||||
sta NB_DOORS
|
||||
lda #<STACK_ADDR
|
||||
sta PTR_STACK ; here stack size < 128, no need for hsb of the address
|
||||
loop_first_door:
|
||||
jsr Random8
|
||||
ldx SIZE_STACK
|
||||
jsr Modulus
|
||||
asl
|
||||
tay
|
||||
lda (PTR_STACK), Y
|
||||
;PTR_TILE = *PTR_STACK - WIDTH_WORLD
|
||||
sec
|
||||
sbc #WIDTH_WORLD
|
||||
sta PTR_TILE
|
||||
iny
|
||||
lda (PTR_STACK), Y
|
||||
sbc #0
|
||||
sta PTR_TILE+1
|
||||
jsr _nb_walkable
|
||||
lda NB_WALKABLE
|
||||
cmp #2
|
||||
bcc loop_first_door ; nb_walkable < 2
|
||||
inc NB_DOORS
|
||||
ldy #WIDTH_WORLD
|
||||
lda #ACTORS::FLOOR_1
|
||||
sta (PTR_TILE), Y
|
||||
|
||||
; # Opening the other doors
|
||||
.define IDX ZERO_2_3
|
||||
lda #<STACK_ADDR
|
||||
sta PTR_STACK ; here stack size < 128, no need for hsb of the address
|
||||
lda #$FF
|
||||
sta IDX
|
||||
loop_other_doors:
|
||||
inc IDX
|
||||
; test if end
|
||||
lda SIZE_STACK
|
||||
asl
|
||||
cmp IDX
|
||||
beq end_loop_other_doors
|
||||
; random number to be compare to the probability of a door
|
||||
jsr Random8
|
||||
cmp PROBABILITY_OPENING
|
||||
bcc test_door
|
||||
beq test_door
|
||||
inc IDX
|
||||
bcs loop_other_doors ; always jump as the previous bcc failed
|
||||
; test if the tile can be linked to the maze
|
||||
test_door:
|
||||
ldy IDX
|
||||
lda (PTR_STACK), Y
|
||||
;PTR_TILE = *PTR_STACK - WIDTH_WORLD
|
||||
sec
|
||||
sbc #WIDTH_WORLD
|
||||
sta PTR_TILE
|
||||
iny
|
||||
lda (PTR_STACK), Y
|
||||
sbc #0
|
||||
sta PTR_TILE+1
|
||||
sty IDX
|
||||
jsr _nb_walkable
|
||||
lda NB_WALKABLE
|
||||
cmp #2
|
||||
bcs carve_a_door
|
||||
bcc loop_other_doors ; always jump as the previous bcs failed
|
||||
carve_a_door:
|
||||
ldy #WIDTH_WORLD
|
||||
lda #ACTORS::FLOOR_1
|
||||
sta (PTR_TILE), Y
|
||||
inc NB_DOORS
|
||||
jmp loop_other_doors
|
||||
end_loop_other_doors:
|
||||
|
||||
dec NB_ROOMS
|
||||
beq end_loop_connect_rooms
|
||||
|
||||
; next room
|
||||
lda OFFSET_ROOMS
|
||||
clc
|
||||
adc #.sizeof(Config_Room)
|
||||
sta OFFSET_ROOMS
|
||||
jmp loop_connect_rooms
|
||||
|
||||
end_loop_connect_rooms:
|
||||
rts
|
||||
|
||||
; @brief returns the number of walkable neighbours. >= 2 if it can be carved
|
||||
; @detailed PTR_TILE is offsetted by -WIDTH_WORLD
|
||||
_nb_walkable:
|
||||
lda #0
|
||||
sta NB_WALKABLE
|
||||
lda #ACTORS::FLOOR_1
|
||||
tst_up:
|
||||
ldy #0
|
||||
cmp (PTR_TILE), Y
|
||||
bne tst_left
|
||||
inc NB_WALKABLE
|
||||
tst_left:
|
||||
ldy #(WIDTH_WORLD-1)
|
||||
cmp (PTR_TILE), Y
|
||||
bne tst_right
|
||||
inc NB_WALKABLE
|
||||
tst_right:
|
||||
ldy #(WIDTH_WORLD+1)
|
||||
cmp (PTR_TILE), Y
|
||||
bne tst_down
|
||||
inc NB_WALKABLE
|
||||
tst_down:
|
||||
ldy #(2*WIDTH_WORLD)
|
||||
cmp (PTR_TILE), Y
|
||||
bne end_is_door_possible
|
||||
inc NB_WALKABLE
|
||||
end_is_door_possible:
|
||||
rts
|
||||
|
||||
.undefine STACK_ADDR
|
||||
.undefine PTR_TILE_TOP
|
||||
.undefine PTR_TILE_BOT
|
||||
.undefine PTR_TILE_LEFT
|
||||
.undefine PTR_TILE_RIGHT
|
||||
.undefine PTR_TILE
|
||||
.undefine PTR_STACK
|
||||
.undefine PROBABILITY_OPENING
|
||||
.undefine NB_DOORS
|
||||
.undefine NB_WALKABLE
|
||||
.undefine SIZE_STACK
|
||||
.undefine WIDTH_ROOM
|
||||
.undefine HEIGHT_ROOM
|
||||
.undefine OFFSET_ROOMS
|
||||
|
18
src/builder/rooms.inc
Normal file
18
src/builder/rooms.inc
Normal file
@ -0,0 +1,18 @@
|
||||
|
||||
; Copyright (C) 2019 Christophe Meneboeuf <christophe@xtof.info>
|
||||
;
|
||||
; This program is free software: you can redistribute it and/or modify
|
||||
; it under the terms of the GNU General Public License as published by
|
||||
; the Free Software Foundation, either version 3 of the License, or
|
||||
; (at your option) any later version.
|
||||
;
|
||||
; This program is distributed in the hope that it will be useful,
|
||||
; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
; GNU General Public License for more details.
|
||||
;
|
||||
; You should have received a copy of the GNU General Public License
|
||||
; along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
.import Carve_Rooms
|
||||
.import Connect_Rooms
|
@ -1,8 +1,11 @@
|
||||
.include "memory.inc"
|
||||
|
||||
; nb of bytes to be displayed in DBG_TRACES[0]
|
||||
.export DBG_TRACE
|
||||
; bytes to be displayed
|
||||
.export DBG_TRACES
|
||||
|
||||
|
||||
.CODE
|
||||
.define STROUT $DB3A ; Applesoft: OUTPUTS AY-POINTED NULL TERMINATED STRING
|
||||
.define LINPTR $ED24 ; Applesoft: Displays the number A(high)X(low) in decimal
|
||||
@ -39,3 +42,6 @@ str_space: .byte " ", 0
|
||||
|
||||
.BSS
|
||||
DBG_TRACES: .res 7 ; bytes to be displayed by TRACE
|
||||