Version presented at the A2FP convention.

New features

  * Levels features can be configured
  * Placing items and monsters
  * Can navigate through many levels
  * Game state can be restored

Many bug corrections
This commit is contained in:
Christophe Meneboeuf 2022-11-21 11:54:23 +01:00
parent 7c90129e9b
commit 261b7276b5
43 changed files with 1767 additions and 1091 deletions

View File

@ -2,21 +2,22 @@ APPLE2_CL := $(CC65_HOME)/bin/cl65
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/player.asm \
src/world/world.asm src/world/level.asm \
src/builder/builder.asm src/builder/actors.asm src/builder/rooms.asm src/builder/maze.asm src/builder/unite.asm \
src/actors/reactions.asm \
src/builder/builder.asm src/builder/rooms.asm src/builder/maze.asm src/builder/unite.asm \
src/actors/reactions.asm src/actors/actors.asm \
src/debug.asm src/display_map.asm \
src/io/title.asm src/io/textio.asm src/io/gr.asm
src/io/title.asm src/io/textio.asm src/io/gr.asm src/io/files.asm
APPLE2_MAP := escape.map
APPLE2_CFLAGS := -Oirs -v -t apple2 -vm --cpu 6502
APPLE2_OUT := bin/escape.a2
APPLE2_OUT := floppy/ESCAPE
all: directories apple2
directories:
mkdir -p bin
all: apple2
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/builder/*.o src/io/*.o src/world/*.o src/actors/*.o gmon.out & rm -r bin/
rm -f $(APPLE2_MAP) floppy/ESCAPE src/*.o src/builder/*.o src/io/*.o src/world/*.o src/actors/*.o gmon.out
install: apple2
./scripts/add-to-disk.sh $(APPLE_COMMANDER) ./floppy escape.dsk

View File

@ -1,37 +1,39 @@
# What is it?
## What is it?
**Escape** (working title) is a homebrew *Rogue-Like** game developped for the Apple II computers.
**Escape** (working title) is a homebrew *Rogue-Like** game developed for the Apple II computers.
It is written in assembly and serves two purposes:
1. Be fun
2. Document the proccess of coding for the Apple II on [my blog](https://www.xtof.info):
- [A tile engine for the Apple II](https://www.xtof.info/an-hires-tile-engine-for-the-apple-ii.html)
- [Raycasting a Line of Sight](https://www.xtof.info/appleii-roguelike-line-of-sight.html)
- [Random level generation on Apple II](https://www.xtof.info/random-level-generation-on-apple-ii.html)
- [A tile engine for the Apple II](https://www.xtof.info/an-hires-tile-engine-for-the-apple-ii.html)
- [Raycasting a Line of Sight](https://www.xtof.info/appleii-roguelike-line-of-sight.html)
- [Random level generation on Apple II](https://www.xtof.info/random-level-generation-on-apple-ii.html)
# How to build
## How to build
## Building
### Prerequisites
Just type
* The build process relies on the assembler provided by the [CC65 compiler suite](https://github.com/cc65/cc65).
* Set the environment variable **CC65_HOME** to the root folder of CC65
* Builds are guaranteed to be successful using version 2.19 (commit 555282497c3ecf8). They should also work with any subsequent versions.
* A makefile compatible with GNU Make is provided.
* [AppleCommander](http://applecommander.sourceforge.net/) is used to produce a disk image that can be loaded in any emulator. Apple Commander requires a Java Runtime.
* Export the variable **APPLE_COMMANDER** to the path of the jar file.
make
### How to build
```bash
make
```
This will produce *bin/escape.a2* which is a binary executable for Apple's II PRODOS.
## Prerequisite in order to build:
```bash
make install
```
The [cc65 compiler suite](https://github.com/cc65/cc65), with the environment variable *CC65_HOME* set to its folder
Will produce the executable binary and copy it along with all the required files into the floppy image *escape.dsk*
Tested OK with version V2.16 - Git be772c01
### How to play
## Prerequisite in order to produce the disk image
- Java Runtime
- [AppleCommander](http://applecommander.sourceforge.net/)
## Embedding the Apple II' executable into the disk image
Run
scripts/add-to-disk.sh
You can navigate the levels using the IJKL keys and display a map by pressing TAB.

BIN
assets/tiles.psd Normal file

Binary file not shown.

55
doc/Doc.md Normal file
View File

@ -0,0 +1,55 @@
# Documentation
## Actors
Actors can be **static** or **dynamic**.
Static actors are immutable while dynamic have a link to their status. Both react to the player's actions. For instance a floor or an opened door will let the player pass, while a table or a monster will block him. Dynamic actors can also have a behavior which can evolute by itself each turn, driven by a finite state machine.
There can be 128 actors of 128 different kinds in a single level. Actor #0 is always the player.
As there are immutable, many instances of a static actor can be represented by a single ID, while each instance of a dynamic actor require a unique ID.
In memory, tiles contain the actor ID, which serves as an offset to render the tile, compute its behavior, and so on.
## Level generation
Read [this page](https://www.xtof.info/random-level-generation-on-apple-ii.html) for a presentation of the general principle concerning the random level generation.
The level configuration is given by the *level.conf* file.
### LEVELS.CONF
Description of the levels for the random builder.
All values are 8-bit integers.
```text
[NB_LEVELS]
# level conf * NB_LEVELS
[NUMBER]
[SIZE]
# number of actors of each types * NB_ACTORS_MAX (128)
[NB_ACTORS]
.
.
.
[NB_ACTORS]
```
### STATES
State of the levels
```text
"LVLS"
CURRENT_LEVEL 1 byte
NB_LEVELS 1 byte
# level state * NB_LEVELS
"LVL"
VISITED 1 byte
PLAYER_TILE 1 byte
LAYOUT 4096 bytes
"ACTS"
# actor state * NB_LEVELS
"ACT"
STATE sizeof(actor_t)
```

Binary file not shown.

BIN
floppy/ESCAPE Normal file

Binary file not shown.

BIN
floppy/LEVELS.ACTS Normal file

Binary file not shown.

BIN
floppy/LEVELS.CONF Normal file

Binary file not shown.

BIN
floppy/STATES Normal file

Binary file not shown.

View File

@ -6,7 +6,7 @@ set -e
if (( $# != 3 )); then
echo "Bad number of arguments"
echo "usage: add_to_disk.sh PATH_TO_APPLECOMMANDER.jar PATH_TO_BINARY.a2 PATH_TO_DISK"
echo "usage: add_to_disk.sh PATH_TO_APPLECOMMANDER.jar PATH_TO_FLOPPYDIR PATH_TO_DISK"
exit
fi
@ -17,9 +17,15 @@ fi
echo " . removing previous instance of ESCAPE from the disk"
java -jar ${1} -d ${3} ESCAPE
java -jar ${1} -d ${3} ESCAPE.SYSTEM
java -jar ${1} -d ${3} LEVELS.CONF
java -jar ${1} -d ${3} LEVELS.ACTS
java -jar ${1} -d ${3} STATES
echo " .. adding ESCAPE and its loader to the disk"
java -jar ${1} -cc65 ${3} ESCAPE BIN < ${2}
echo " .. adding files to the disk"
java -jar ${1} -as ${3} ESCAPE BIN < ${2}/ESCAPE
java -jar ${1} -p ${3} ESCAPE.SYSTEM SYS < ${CC65_HOME}/target/apple2/util/loader.system
java -jar ${1} -p ${3} LEVELS.CONF BIN < ${2}/LEVELS.CONF
java -jar ${1} -p ${3} LEVELS.ACTS BIN < ${2}/LEVELS.ACTS
java -jar ${1} -p ${3} STATES BIN < ${2}/STATES
echo "DONE."

185
src/actors/actors.asm Normal file
View File

@ -0,0 +1,185 @@
.include "../common.inc"
.include "../random.inc"
.include "../memory.inc"
.include "../math.inc"
.include "../world/world.inc"
.include "actors.inc"
.import Rooms
.import World
.import Compute_Maze_Addr
.export ActorsInLevel
.export ActorPositions
.export ActorStates
.export ActorTypes
.export ActorTransparent
.BSS
; struc actors_t {
.align 256
ActorsInLevel:
; aligned 256
ActorPositions: .res 256 ; coords_t positions[NB_ACTORS_MAX];
; aligned 256
ActorStates: .res 256 ; actor_state_t* states[NB_ACTORS_MAX];
; aligned 256
ActorTypes: .res 128 ; uint8_t types[NB_ACTORS_MAX];
; }
; NOTE: Modify SIZEOF_ACTORS_T if necessary!!
.RODATA
.align 256
ActorTransparent: ; NB_ACTORS_MAX
; player
.byte TRUE
; floors
.byte TRUE, TRUE, TRUE, TRUE, TRUE, TRUE
; walls
.byte FALSE, FALSE, FALSE, FALSE
; stair down
.byte TRUE
; stair up
.byte FALSE
; monsters
.byte TRUE, TRUE, TRUE
; others
.byte TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE
.byte TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE
.byte TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE
.byte TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE
.byte TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE
.byte TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE
.byte TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE, TRUE
.CODE
; code
.export Place_Actors
.export Actors_Init
Actors_Init:
; positions
ldx #(2*NB_ACTORS_MAX - 1)
lda #UNDEF
loop_actors_pos_init:
sta ActorPositions, x
dex
bne loop_actors_pos_init
; types
ldx #eACTORTYPES::LAST_STATIC
loop_actors_types_init:
txa
sta ActorTypes, X
dex
bne loop_actors_types_init
ldx #eACTORTYPES::LAST_MONSTER+1
loop_actors_types_init_2:
txa
sta ActorTypes, X
inx
cpx #eACTORTYPES::NB_ACTORS
bne loop_actors_types_init_2
rts
.define PTR_ROOM ZERO_2_1 ; 2 bytes
.define PTR_TILE ZERO_2_1 ; 2 bytes
; the two following defines must be the same as in Build_Level
.define ROOM_X ZERO_3
.define ROOM_Y ZERO_2_4
.define ROOM_W ZERO_2_5
.define ROOM_H ZERO_2_6
; parameters:
.define NB_ROOMS ZERO_9_9
.define ACTOR_ID ZERO_9_1
.define ACTOR_TYPE ZERO_9_2
Place_Actors:
loop_find_location:
jsr Random8
ldx NB_ROOMS
jsr Modulus
; sizeof(room_t) == 4
asl
asl
clc
adc #<Rooms
sta PTR_ROOM
lda #0
adc #>Rooms
sta PTR_ROOM+1
ldy #0
lda (PTR_ROOM), Y
sta ROOM_H
iny
lda (PTR_ROOM), Y
sta ROOM_W
iny
lda (PTR_ROOM), Y
sta ROOM_X
iny
lda (PTR_ROOM), Y
sta ROOM_Y
; x = room->x + rand() % (room->width - 2) + 1;
sec
lda ROOM_W
sbc #2
sta ROOM_W
jsr Random8
ldx ROOM_W
jsr Modulus
clc
adc ROOM_X
adc #1
sta ROOM_X
; y = room->y + rand() % (room->height - 2) + 1;
sec
lda ROOM_H
sbc #2
sta ROOM_H
jsr Random8
ldx ROOM_H
jsr Modulus
clc
adc ROOM_Y
adc #1
sta ROOM_Y
tay
ldx ROOM_X
jsr Compute_Maze_Addr
stx PTR_TILE
sta PTR_TILE+1
ldy #0
lda (PTR_TILE), Y
cmp #eACTORTYPES::FLOOR_2
bne loop_find_location
; save position
ldx ACTOR_ID
lda ROOM_X
sta ActorPositions, X
lda ROOM_Y
sta ActorPositions+1, X
; save type
lda ACTOR_TYPE
sta ActorTypes, X
txa
sta (PTR_TILE), Y
rts

46
src/actors/actors.inc Normal file
View File

@ -0,0 +1,46 @@
.define NB_ACTORS_MAX 128
.define SIZEOF_ACTORS_T 256+256+128
.enum eACTORTYPES
PLAYER = 0 ; PLAYER MUST ALWAYS BE 0
; STATIC ACTORS
; FLOOR
FLOOR_1 = 1
FLOOR_2 ; FLOOR BY DEFAULT
FLOOR_3
FLOOR_4
FLOOR_5
FLOOR_6
LAST_FLOOR = FLOOR_6
; WALLS
WALL_1
WALL_2
WALL_3
WALL_4
LAST_STATIC = WALL_4
; DYNAMIC ACTORS
STAIR_DOWN ; 11
FIRST_DYNAMIC = STAIR_DOWN
STAIR_UP
; ITEMS
MAP ; 13
; MONSTERS
RAT ; 14
FIRST_MONSTER = RAT
TARENTULA
SERPENT
LAST_MONSTER = SERPENT ;16
NB_ACTORS = 127
UNKNOWN = NB_ACTORS
.endenum

View File

@ -13,7 +13,7 @@
; 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 "actors.inc"
.include "../world/level.inc"
.include "../io/textio.inc"
.include "../common.inc"
@ -22,20 +22,39 @@
.export Reactions_msb
.export ReactionStairUp
.export ReactionStairDown
.export ReactionMap
.import ActorPositions
.import World_PickedObject
.DATA
STR_REATION_WALL: ASCIIZ "YOU HIT A WALL"
STR_REATION_STAIR_UP: ASCIIZ "YOU GO UPSTAIRS TO THE PREVIOUS LEVEL"
STR_REATION_STAIR_DOWN: ASCIIZ "YOU GO DOWNSTAIRS TO THE NEXT LEVEL"
STR_REACTION_WALL: ASCIIZ "YOU HIT A WALL"
STR_REACTION_STAIR_UP: ASCIIZ "YOU GO UPSTAIRS TO TO THE NEXT LEVEL"
STR_REACTION_STAIR_DOWN: ASCIIZ "YOU GO DOWNSTAIRS THE PREVIOUS LEVEL"
STR_REACTION_MAP: ASCIIZ "YOU FOUND A MAP!"
STR_REACTION_RAT: ASCIIZ "YOU ATTACK THE RAT"
STR_REACTION_SPIDER: ASCIIZ "YOU ATTACK THE SPIDER"
STR_REACTION_SERPENT: ASCIIZ "YOU ATTACK THE SERPENT"
.align 256
; functions address seperated in LSB / MSB to use the same X/Y offset
; They must be in the very same order as the actor's types
Reactions_lsb:
.byte 0, <ReactionFloor, <ReactionFloor, <ReactionFloor, <ReactionFloor, <ReactionFloor, <ReactionFloor, <ReactionStairDown
.byte <ReactionStairUp, <ReactionWall, <ReactionWall, <ReactionWall, <ReactionWall, 0, 0, 0
.byte 0, 0, 0, 0, 0, 0, 0, 0
; player
.byte 0
; floors
.byte <ReactionFloor, <ReactionFloor, <ReactionFloor, <ReactionFloor, <ReactionFloor, <ReactionFloor
; walls
.byte <ReactionWall, <ReactionWall, <ReactionWall, <ReactionWall
; stairs
.byte <ReactionStairDown, <ReactionStairUp
; items
.byte <ReactionMap
; monsters
.byte <ReactionRat, <ReactionSpider, <ReactionSerpent
; other
.byte 0, 0, 0, 0, 0, 0, 0, 0
.byte 0, 0, 0, 0, 0, 0, 0, 0
.byte 0, 0, 0, 0, 0, 0, 0, 0
@ -65,11 +84,22 @@ Reactions_lsb:
.byte 0, 0, 0, 0, 0, 0, 0, 0
.byte 0, 0, 0, 0, 0, 0, 0, 0
.byte 0, 0, 0, 0, 0, 0, 0, 0
.byte 0, 0, 0, 0, 0, 0, 0
Reactions_msb:
.byte 0, >ReactionFloor, >ReactionFloor, >ReactionFloor, >ReactionFloor, >ReactionFloor, >ReactionFloor, >ReactionStairDown
.byte >ReactionStairUp, >ReactionWall, >ReactionWall, >ReactionWall, >ReactionWall, 0, 0, 0
.byte 0, 0, 0, 0, 0, 0, 0, 0
; player
.byte 0
; floors
.byte >ReactionFloor, >ReactionFloor, >ReactionFloor, >ReactionFloor, >ReactionFloor, >ReactionFloor
; walls
.byte >ReactionWall, >ReactionWall, >ReactionWall, >ReactionWall
; stairs
.byte >ReactionStairDown, >ReactionStairUp
; items
.byte >ReactionMap
; monsters
.byte >ReactionRat, >ReactionSpider, >ReactionSerpent
; others
.byte 0, 0, 0, 0, 0, 0, 0, 0
.byte 0, 0, 0, 0, 0, 0, 0, 0
.byte 0, 0, 0, 0, 0, 0, 0, 0
@ -99,35 +129,70 @@ Reactions_msb:
.byte 0, 0, 0, 0, 0, 0, 0, 0
.byte 0, 0, 0, 0, 0, 0, 0, 0
.byte 0, 0, 0, 0, 0, 0, 0, 0
.byte 0, 0, 0, 0, 0, 0, 0
.CODE
ReactionFloor:
lda TRUE
lda #TRUE
rts
ReactionWall:
PRINT STR_REATION_WALL
lda FALSE
PRINT STR_REACTION_WALL
lda #FALSE
rts
ReactionStairUp:
PRINT STR_REATION_STAIR_UP
PRINT STR_REACTION_STAIR_UP
lda CurrentLevel
sta NextLevel
inc NextLevel
lda TRUE
lda #TRUE
sta ExitLevel
lda FALSE
lda #FALSE
rts
ReactionStairDown:
PRINT STR_REATION_STAIR_DOWN
PRINT STR_REACTION_STAIR_DOWN
lda CurrentLevel
sta NextLevel
dec NextLevel
lda TRUE
lda #TRUE
sta ExitLevel
lda FALSE
lda #FALSE
rts
; @param actor_id in X
ReactionMap:
; index of &ActorPositions[actor_id]
txa
asl
tax
lda #UNDEF
sta ActorPositions, X
sta ActorPositions+1, X
PRINT STR_REACTION_MAP
lda #TRUE
sta World_PickedObject
rts
ReactionRat:
PRINT STR_REACTION_RAT
lda #FALSE
rts
ReactionSpider:
PRINT STR_REACTION_SPIDER
lda #FALSE
rts
ReactionSerpent:
PRINT STR_REACTION_SERPENT
lda #FALSE
rts

View File

@ -1,107 +0,0 @@
.include "../common.inc"
.include "../random.inc"
.include "../memory.inc"
.include "../math.inc"
.include "../world/world.inc"
.include "actors_private.inc"
.import Rooms
.import World
.import Compute_Maze_Addr
; code
.export Place_Actors
; data
.export ActiveActor_Tiles
.DATA
ActiveActor_Tiles: .byte ACTORS::STAIR_UP, ACTORS::STAIR_DOWN, ACTORS::FLOOR_1 ; DEBUg: placeholder for future map
.CODE
.define PTR_ROOM ZERO_2_1 ; 2 bytes
.define PTR_TILE ZERO_2_1 ; 2 bytes
; the two following defines must be the same as in Build_Level
.define ROOM_X ZERO_3
.define ROOM_Y ZERO_2_4
.define ROOM_W ZERO_2_5
.define ROOM_H ZERO_2_6
.define NB_ROOMS ZERO_9_9
.define ACTOR ZERO_9_10
; A : ACTOR
; X : NB_ROOMS
Place_Actors:
sta ACTOR
stx NB_ROOMS
loop_find_location:
jsr Random8
ldx NB_ROOMS
jsr Modulus
; sizeof(room_t) == 4
asl
asl
clc
adc #<Rooms
sta PTR_ROOM
lda #0
adc #>Rooms
sta PTR_ROOM+1
ldy #0
lda (PTR_ROOM), Y
sta ROOM_H
iny
lda (PTR_ROOM), Y
sta ROOM_W
iny
lda (PTR_ROOM), Y
sta ROOM_X
iny
lda (PTR_ROOM), Y
sta ROOM_Y
; x = room->x + rand() % (room->width - 2) + 1;
sec
lda ROOM_W
sbc #2
sta ROOM_W
jsr Random8
ldx ROOM_W
jsr Modulus
clc
adc ROOM_X
adc #1
sta ROOM_X
; y = room->y + rand() % (room->height - 2) + 1;
sec
lda ROOM_H
sbc #2
sta ROOM_H
jsr Random8
ldx ROOM_H
jsr Modulus
clc
adc ROOM_Y
adc #1
sta ROOM_Y
tay
ldx ROOM_X
jsr Compute_Maze_Addr
stx PTR_TILE
sta PTR_TILE+1
ldy #0
lda (PTR_TILE), Y
cmp #ACTORS::FLOOR_2
bne loop_find_location
lda ACTOR
sta (PTR_TILE), Y
rts

View File

@ -1,7 +1,32 @@
.include "actors_private.inc"
.define NB_ACTORS_MAX 128
; code
.import Place_Actors
; data
.import ActiveActor_Tiles
.enum ACTORS
PLAYER = 0
; FLOOR
FLOOR_1 = 1
FLOOR_2 ; FLOOR BY DEFAULT
FLOOR_3
FLOOR_4
FLOOR_5
FLOOR_6
STAIR_DOWN
; OBJECT
MAP
; WALLS
STAIR_UP
WALKABLE = STAIR_UP ; Player won't be allowed to go on anything > WALKABLE
NOT_TRANSPARENT = STAIR_UP
NOT_WALKABLE
WALL_1 = NOT_WALKABLE
WALL_2
UNKNOWN
NB_ACTORS
.endenum

View File

@ -1,7 +0,0 @@
; @brief All kind of reactive actors that can be in a level
.enum eACTORSREACTIVE
AA_STAIRUP = 0
AA_STAIRDOWN
AA_MAP
AA_NB
.endenum

View File

@ -20,7 +20,8 @@
.include "rooms.inc"
.include "maze.inc"
.include "unite.inc"
.include "actors.inc"
.include "../common.inc"
.include "../actors/actors.inc"
.include "../io/textio.inc"
.include "../math.inc"
.include "../monitor.inc"
@ -28,12 +29,15 @@
.include "../world/world.inc"
.include "../world/level.inc"
.import World
; code
.import Random8
.import Grow_Maze ; to patch
.import Compute_Maze_Addr
.import Place_Actors
; data
.import World
.import Tile_player_standing_actor
.export Get_Size_Maze
.export Init_Dimensions_Maze
.export Build_Level
@ -69,56 +73,11 @@ STR_DEADENDS: ASCIIZ "FILLING DEAD ENDS..."
STR_UNITE: ASCIIZ "UNITING THE ROOMS..."
STR_ACTORS: ASCIIZ "PLACING ACTORS..."
.CODE
; DEPRECATED!!!
; @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 #LEVELSIZE::TINY
ldy #LEVELSIZE::TINY
rts
tst_small:
cmp #$C2
bne tst_medium
ldx #LEVELSIZE::SMALL
ldy #LEVELSIZE::SMALL
rts
tst_medium:
cmp #$C3
bne tst_big
ldx #LEVELSIZE::NORMAL
ldy #LEVELSIZE::NORMAL
rts
tst_big:
cmp #$C4
bne tst_huge
ldx #LEVELSIZE::BIG
ldy #LEVELSIZE::BIG
rts
tst_huge:
cmp #$C5
bne bad_size
ldx #LEVELSIZE::HUGE
ldy #LEVELSIZE::HUGE
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
@ -198,15 +157,18 @@ Init_Dimensions_Maze:
; @return player position in X and Y
.define DST_WORLD World
.define ADDR_TO_PATCH init_world_line + 3
.define NB_ROOMS ZERO_9_9
.define NB_ROOMS ZERO_9_9 ; use same location as Place_Actors
Build_Level:
; Filling World with ACTORS::WALL_1
lda #UNDEF
sta Tile_player_standing_actor
; Filling World with eACTORTYPES::WALL_1
ldy #HEIGHT_WORLD
init_world:
ldx #0
init_world_line:
lda #ACTORS::WALL_1
lda #eACTORTYPES::WALL_1
sta DST_WORLD, x
inx
cpx #WIDTH_WORLD
@ -225,20 +187,21 @@ Build_Level:
lda #<DST_WORLD
sta ADDR_TO_PATCH
lda #>DST_WORLD
sta ADDR_TO_PATCH+1
sta ADDR_TO_PATCH+1
PRINT STR_ROOMS
lda #MAX_NB_ROOMS+1
jsr Carve_Rooms
sta NB_ROOMS
lda #ACTORS::FLOOR_1
jsr _build_fences
lda #eACTORTYPES::FLOOR_1
jsr _build_fences
PRINT STR_MAZE
jsr Grow_Maze
lda #ACTORS::WALL_1
lda #eACTORTYPES::WALL_1
jsr _build_fences
PRINT STR_DOORS
@ -252,50 +215,51 @@ Build_Level:
PRINT STR_UNITE
jsr Unite_Rooms
PRINT STR_ACTORS
; the two following defines must be the same as in Place_Actors
.define POS_X ZERO_3 ; ROOM_X in Place_Actors
.define POS_Y ZERO_2_4 ; ROOM_Y in Place_Actors
.define POS_STARDOWN_X ZERO_5_1
.define POS_STARDOWN_Y ZERO_5_2
.define ACTOR ZERO_4_1
.define ACTOR_NB ZERO_4_2
.define CURR_ACTOR_OFFSET ZERO_4_3
.define POS_PLAYER_OFFSET ZERO_4_4
.define LEVEL_CONF_OFFSET ZERO_5_3
.define ADDR_ACTOR ZERO_4_3 ; 2 bytes
.define ACTOR_ID ZERO_9_1 ; use same location as Place_Actors
.define ACTOR_TYPE ZERO_9_2 ; use same location as Place_Actors
.define CURR_ACTOR_OFFSET ZERO_4_3
.define ADDR_LEVEL_CONF ZERO_5_3 ; 2 bytes
.define ADDR_ACTOR ZERO_4_3 ; 2 bytes
lda #0
sta ACTOR
ldx NextLevel
stx FAC1
ldx #SIZEOF_CONF_LEVEL
stx FAC2
jsr mul8 ; A = offset to level conf
txa
sta LEVEL_CONF_OFFSET
; place actors
PRINT STR_ACTORS
; offset to level conf
lda NextLevel
jsr level_get_config_offset
pha
clc
adc #7 ; A = offset to pos_player_enter
sta POS_PLAYER_OFFSET
tax
inx
inx ; offset to actors[AA_NB]
loop_actors:
stx CURR_ACTOR_OFFSET
lda Levels, X ; actors[AA_NB]
txa
adc #<LevelConfigs
sta ADDR_LEVEL_CONF
pla
adc #>LevelConfigs
sta ADDR_LEVEL_CONF+1
lda #eACTORTYPES::LAST_STATIC + 1 ; 1st dynamic actor id
sta ACTOR_ID
sta ACTOR_TYPE
tay
iny
iny ; offset to actors[ACTOR_ID] in level conf
loop_actors: ; loop over actors from conf
sty CURR_ACTOR_OFFSET
lda (ADDR_LEVEL_CONF), Y
sta ACTOR_NB
loop_actor_nb:
beq end_loop_actor_nb
loop_actor_id:
beq end_loop_actor_id
ldx ACTOR
lda ActiveActor_Tiles, X
ldx NB_ROOMS
jsr Place_Actors
jsr Place_Actors
; save stair down position
lda ACTOR
cmp #eACTORSREACTIVE::AA_STAIRDOWN
lda ACTOR_TYPE
cmp #eACTORTYPES::STAIR_DOWN
bne not_stair_down
lda POS_X
sta POS_STARDOWN_X
@ -303,31 +267,29 @@ Build_Level:
sta POS_STARDOWN_Y
not_stair_down:
inc ACTOR_ID
dec ACTOR_NB ; next
jmp loop_actor_nb
end_loop_actor_nb:
lda ACTOR_NB
jmp loop_actor_id
end_loop_actor_id:
ldx CURR_ACTOR_OFFSET
inx
inc ACTOR
ldy ACTOR
cpy #eACTORSREACTIVE::AA_NB
ldy CURR_ACTOR_OFFSET
iny
inc ACTOR_TYPE
lda ACTOR_TYPE
cmp #(NB_ACTORS_MAX-1)
bne loop_actors
; Set the 1st position of the player in the level
ldx POS_PLAYER_OFFSET
lda Levels, X
cmp #$FF
bne not_first_entry
; Very first entrance in the level
lda NextLevel
cmp #0
bne not_first_level
; Special case: first level
; TODO avoid non empty floor...
ldx Rooms+2 ; Rooms[0].x
ldy Rooms+3 ; Rooms[0].y
rts
; offset to level state
lda NextLevel
cmp #0
bne not_first_level
; Special case: first level
; TODO avoid non empty floor...
ldx Rooms+2 ; Rooms[0].x
ldy Rooms+3 ; Rooms[0].y
rts
not_first_level:
ldx POS_STARDOWN_X
ldy POS_STARDOWN_Y
@ -346,7 +308,7 @@ Build_Level:
; if (World[pos_stair_down.y][pos_stair_down.x - 1] == FLOOR_2)
ldy #(WIDTH_WORLD - 1)
lda (ADDR_ACTOR), Y
cmp #ACTORS::FLOOR_2
cmp #eACTORTYPES::FLOOR_2
bne not_x_minus
ldy POS_STARDOWN_Y
dex
@ -355,7 +317,7 @@ Build_Level:
; if (World[pos_stair_down.y - 1][pos_stair_down.x] == FLOOR_2)
ldy #0
lda (ADDR_ACTOR), Y
cmp #ACTORS::FLOOR_2
cmp #eACTORTYPES::FLOOR_2
bne not_y_minus
ldy POS_STARDOWN_Y
dey
@ -364,7 +326,7 @@ Build_Level:
; if (World[pos_stair_down.y + 1][pos_stair_down.x] == FLOOR_2)
ldy #(WIDTH_WORLD * 2)
lda (ADDR_ACTOR), Y
cmp #ACTORS::FLOOR_2
cmp #eACTORTYPES::FLOOR_2
bne not_y_plus
ldy POS_STARDOWN_Y
iny
@ -372,23 +334,6 @@ Build_Level:
not_y_plus:
ldy POS_STARDOWN_Y
inx
rts
not_first_entry:
pha ; pos_player_enter.x
inx
lda Levels, X ; pos_player_enter.y
tay
pla
tax
rts
; ldx NB_ROOMS
; lda #ACTORS::STAIR_DOWN
; jsr Place_Actors
; lda #ACTORS::STAIR_UP
; ldx NB_ROOMS
; jsr Place_Actors
rts

View File

@ -13,7 +13,6 @@
; 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

View File

@ -18,6 +18,7 @@
.include "../math.inc"
.include "../common.inc"
.include "../world/world.inc"
.include "../actors/actors.inc"
.export Grow_Maze
@ -121,7 +122,7 @@
.macro ISWALKABLE offset
ldy offset
lda (PTR_NEW_TILE),Y
cmp #ACTORS::WALKABLE+1
cmp #eACTORTYPES::LAST_FLOOR+1
bcc cannot_carve
.endmacro
@ -139,27 +140,27 @@
ldy OFFSET_NIL
lda (PTR_NEW_TILE),Y
cmp #ACTORS::WALKABLE
cmp #eACTORTYPES::LAST_FLOOR
bcc end_loop_stack
ldy OFFSET_UP
lda (PTR_NEW_TILE),Y
cmp #ACTORS::WALKABLE
cmp #eACTORTYPES::LAST_FLOOR
bcc end_loop_stack
ldy OFFSET_RIGHT
lda (PTR_NEW_TILE),Y
cmp #ACTORS::WALKABLE
cmp #eACTORTYPES::LAST_FLOOR
bcc end_loop_stack
ldy OFFSET_DOWN
lda (PTR_NEW_TILE),Y
cmp #ACTORS::WALKABLE
cmp #eACTORTYPES::LAST_FLOOR
bcc end_loop_stack
ldy OFFSET_LEFT
lda (PTR_NEW_TILE),Y
cmp #ACTORS::WALKABLE
cmp #eACTORTYPES::LAST_FLOOR
bcc end_loop_stack
.endmacro
@ -194,7 +195,7 @@ loop_grow_maze:
; carve
ldy #WIDTH_WORLD
lda #ACTORS::FLOOR_1
lda #eACTORTYPES::FLOOR_1
sta (PTR_NEW_TILE),Y
@ -236,7 +237,7 @@ loop_grow_maze:
carve_the_tile:
; carve the tile
ldy #0
lda #ACTORS::FLOOR_1
lda #eACTORTYPES::FLOOR_1
sta (PTR_NEW_TILE),Y
jmp loop_stack
end_loop_stack:
@ -438,7 +439,7 @@ _follow_dead_end:
loop_follow:
ldy #WIDTH_WORLD
lda #ACTORS::WALL_1
lda #eACTORTYPES::WALL_1
sta (PTR_TILE), Y
lda PTR_NEXT_TILE
@ -462,7 +463,7 @@ _follow_dead_end:
rts
.define ADD_FACTOR ZERO_4_1
.define ADD_FACTOR ZERO_4_3
; 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
@ -474,7 +475,7 @@ _is_tile_dead_end:
sty ADD_FACTOR
; Returns if the tile is a wall
lda #ACTORS::WALKABLE
lda #eACTORTYPES::LAST_FLOOR
cmp (PTR_TILE), Y
bcc end_tst_up_tile

View File

@ -19,6 +19,7 @@
.include "../math.inc"
.include "../common.inc"
.include "../world/world.inc"
.include "../actors/actors.inc"
.export Carve_Rooms
.export Connect_Rooms
@ -33,6 +34,7 @@
.BSS
; Configration to build rooms
; FIXME??? CA65 will locate this struct at address 0 !!!
.struct Config_Room
width_min .byte
width_max .byte
@ -73,18 +75,17 @@ Carve_Rooms:
lda NB_ROOMS_OK ; NB_ROOMS_OK*sizeof(room_t) -> X
asl
asl
tax
tax
jsr _Build_Room
lda NB_ROOMS_OK
jsr _Is_intersecting
cmp TRUE ; not intersecting with another room?
cmp #TRUE ; not intersecting with another room?
beq loop_rooms
inc NB_ROOMS_OK
clc
bcc loop_rooms
jmp loop_rooms
end_loop_rooms:
@ -106,8 +107,7 @@ Carve_Rooms:
end_loop_draw_rooms:
lda NB_ROOMS_OK
lda NB_ROOMS_OK
rts
.undefine NB_ATTEMPTS
@ -142,7 +142,7 @@ _Draw_Room:
lda Rooms+1, X ; room->width
sta LINE_LENGTH
loop_draw_line:
lda #ACTORS::FLOOR_1
lda #eACTORTYPES::FLOOR_1
ldy #0
loop_draw_tile:
sta (ADDR_WORLD), Y
@ -272,7 +272,7 @@ _Is_intersecting:
cmp #0
bne compare
; first room
lda FALSE
lda #FALSE
clc
bcc end_intersecting ; branch always
@ -308,7 +308,7 @@ compare:
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
lda #TRUE ; return value
clc
bcc end_intersecting
@ -320,7 +320,7 @@ compare:
dec NB_ROOMS
bne loop_intersecting
lda FALSE ; no room intersects
lda #FALSE ; no room intersects
end_intersecting:
rts
@ -554,7 +554,7 @@ Connect_Rooms:
bcc loop_first_door ; nb_walkable < 2
inc NB_DOORS
ldy #WIDTH_WORLD
lda #ACTORS::FLOOR_1
lda #eACTORTYPES::FLOOR_1
sta (PTR_TILE), Y
; # Opening the other doors
@ -597,7 +597,7 @@ Connect_Rooms:
bcc loop_other_doors ; always jump as the previous bcs failed
carve_a_door:
ldy #WIDTH_WORLD
lda #ACTORS::FLOOR_1
lda #eACTORTYPES::FLOOR_1
sta (PTR_TILE), Y
inc NB_DOORS
jmp loop_other_doors
@ -621,7 +621,7 @@ Connect_Rooms:
_nb_walkable:
lda #0
sta NB_WALKABLE
lda #ACTORS::FLOOR_1
lda #eACTORTYPES::FLOOR_1
tst_up:
ldy #0
cmp (PTR_TILE), Y

View File

@ -23,6 +23,7 @@
.include "../math.inc"
.include "../common.inc"
.include "../world/world.inc"
.include "../actors/actors.inc"
.import World
.import Rooms
@ -33,9 +34,7 @@
.export Unite_Rooms
.BSS
.DATA
.CODE
@ -62,7 +61,7 @@ _Flood_Fill :
ldy #0
cmp (PTR_TILE), Y ; if (*ptr_tile != replaced) return;
beq fill_1
lda FALSE
lda #FALSE
rts
fill_1:
@ -114,7 +113,7 @@ fill_1:
lda FILL_NR
sta (PTR_TILE_LOCAL),Y
; *(++ptr_queue) = tile_w
ADD16 PTR_QUEUE, #2
ADD16 PTR_QUEUE, #2, #0
clc
lda #1
adc PTR_TILE_LOCAL
@ -136,7 +135,7 @@ fill_1:
lda FILL_NR
sta (PTR_TILE_LOCAL),Y
; *(++ptr_queue) = tile_tile_east
ADD16 PTR_QUEUE, #2
ADD16 PTR_QUEUE, #2, #0
sec
lda PTR_TILE_LOCAL
sbc #1
@ -157,7 +156,7 @@ fill_1:
lda FILL_NR
sta (PTR_TILE_LOCAL),Y
; *(++ptr_queue) = tile_tile_north
ADD16 PTR_QUEUE, #2
ADD16 PTR_QUEUE, #2, #0
sec
lda PTR_TILE_LOCAL
sbc #WIDTH_WORLD
@ -178,7 +177,7 @@ fill_1:
lda FILL_NR
sta (PTR_TILE_LOCAL),Y
; *(++ptr_queue) = tile_tile_south
ADD16 PTR_QUEUE, #2
ADD16 PTR_QUEUE, #2, #0
clc
lda #WIDTH_WORLD
adc PTR_TILE_LOCAL
@ -194,7 +193,7 @@ fill_1:
end_fill:
lda TRUE
lda #TRUE
rts
@ -202,7 +201,7 @@ end_fill:
.define ROOM_NR ZERO_3
.define SAVE_X ZERO_4_1
.define PTR_ROOM ZERO_4_2 ; 2 bytes
.define ZONE_0 ACTORS::FLOOR_1 ; 1st useful zone: ZONE_1
.define ZONE_0 eACTORTYPES::FLOOR_1 ; 1st useful zone: ZONE_1
Unite_Rooms:
; *** flood fill room to identify separated zones ***
@ -226,13 +225,13 @@ Unite_Rooms:
ldx ZONE_NR
lda #ZONE_0
jsr _Flood_Fill
cmp TRUE
cmp #TRUE
bne loop_flood_next
inc ZONE_NR
loop_flood_next:
;next tile
ADD16 PTR_TILE, #1
ADD16 PTR_TILE, #1, #0
; end line?
inc CPT_X
ldx CPT_X
@ -241,7 +240,7 @@ Unite_Rooms:
ldx #0
stx CPT_X
; next
ADD16 PTR_TILE, #1
ADD16 PTR_TILE, #1, #0
; the end?
inc CPT_Y
ldy CPT_Y
@ -460,7 +459,7 @@ _Connect_Room:
while_1:
; ptr_room += ix
patch_ix1:
ADD16 PTR_ROOM, #1
ADD16 PTR_ROOM, #1, #0
; d += dy2
clc
lda DELTA_Y_2
@ -474,7 +473,7 @@ _Connect_Room:
lda (PTR_ROOM), Y ; Y = 0
cmp ZONE_NR
beq continue_1a
cmp #ACTORS::WALKABLE
cmp #eACTORTYPES::LAST_FLOOR
beq end
bpl continue_1a
jmp end
@ -484,7 +483,7 @@ _Connect_Room:
sta (PTR_ROOM), Y ; Y = 0
; ptr_room += iy
patch_iy1:
ADD16 PTR_ROOM, #WIDTH_WORLD
ADD16 PTR_ROOM, #WIDTH_WORLD, #0
; d -= dx2
sec
lda D
@ -495,7 +494,7 @@ _Connect_Room:
lda (PTR_ROOM), Y ; Y = 0
cmp ZONE_NR
beq continue_1b
cmp #ACTORS::WALKABLE
cmp #eACTORTYPES::LAST_FLOOR
beq end
bpl continue_1b
jmp end
@ -517,7 +516,7 @@ _Connect_Room:
while_2:
; ptr_room += iy
patch_iy2:
ADD16 PTR_ROOM, #WIDTH_WORLD
ADD16 PTR_ROOM, #WIDTH_WORLD, #0
; d += dx2
clc
lda DELTA_X_2
@ -531,7 +530,7 @@ _Connect_Room:
lda (PTR_ROOM), Y ; Y = 0
cmp ZONE_NR
beq continue_2a
cmp #ACTORS::WALKABLE
cmp #eACTORTYPES::LAST_FLOOR
beq end
bpl continue_2a
jmp end
@ -541,7 +540,7 @@ _Connect_Room:
sta (PTR_ROOM), Y ; Y = 0
; ptr_room += ix;
patch_ix2:
ADD16 PTR_ROOM, #1
ADD16 PTR_ROOM, #1, #0
; d -= dy2
sec
lda D
@ -552,7 +551,7 @@ _Connect_Room:
lda (PTR_ROOM), Y ; Y = 0
cmp ZONE_NR
beq continue_2b
cmp #ACTORS::WALKABLE
cmp #eACTORTYPES::LAST_FLOOR
beq end