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
bpl continue_2b
jmp end

View File

@ -13,5 +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/>.
.define TRUE #1
.define FALSE #0
.define TRUE 1
.define FALSE 0
.define UNDEF $FF

View File

@ -15,11 +15,13 @@
; along with this program. If not, see <http://www.gnu.org/licenses/>.
.include "world/world.inc"
.include "actors/actors.inc"
.include "display.inc"
.include "tiles.inc"
.include "math.inc"
.include "memory.inc"
.include "monitor.inc"
.include "common.inc"
; Init the view. To be called before anything else!
@ -44,6 +46,8 @@
.import Compute_Maze_Addr
.import World
.import Player_XY
.import ActorTransparent
.import ActorTypes
.import DBG_TRACE
.import DBG_TRACES
@ -97,20 +101,6 @@ loop_view_init:
rts
; this routines populates View_Future, without any LOS
_dbg_build_view:
lda #0
ldx #(GRID_WIDTH * GRID_HEIGHT - 1)
loop_build_view:
lda #ACTORS::PLAYER
sta View_Future,X
dex
bne loop_build_view
sta View_Future,X
rts
; this routine will create the view and populate View_Future
; destroys ZERO_4_3, ZERO_4_4, ZERO_5_1, ZERO_5_2, ZERO_5_3
; ZERO_5_4, ZERO_5_5, ZERO_5_6, ZERO_7_1, ZERO_7_2
@ -120,7 +110,7 @@ _build_view:
lda #0
ldx #(GRID_WIDTH * GRID_HEIGHT - 1)
loop_init_view:
lda #ACTORS::UNKNOWN
lda #eACTORTYPES::UNKNOWN
sta View_Future,X
dex
bne loop_init_view
@ -129,7 +119,7 @@ _build_view:
; 2 - Player
.define OFFSET_PLAYER_IN_VIEW PLAYER_X+PLAYER_Y*GRID_WIDTH
ldx #(OFFSET_PLAYER_IN_VIEW)
lda #ACTORS::PLAYER
lda #eACTORTYPES::PLAYER
sta View_Future,X
; 3 - Casting rays
@ -140,6 +130,7 @@ _build_view:
.define SRC_TILE_IN_WORLD ZERO_5_2 ; 2 bytes
.define PTR_RAY ZERO_5_4 ; 2 bytes
.define TMP ZERO_5_6
.define TMP2 ZERO_7_1
; loading ptr_rays - 1 as it will be incremented
@ -197,15 +188,21 @@ _build_view:
iny
sty TMP
lda (PTR_RAY),Y ; offset_view
tax
sta TMP2
ldy #0
lda (SRC_TILE_IN_WORLD),Y
sta View_Future,X
lda (SRC_TILE_IN_WORLD), Y
; sta View_Future, X ; ptr tile in view future
ldy TMP
iny
; break if non-transparent
cmp #ACTORS::NOT_TRANSPARENT
bcs end_loop_ray
; break if non-transparent
tax
lda ActorTypes, X
ldx TMP2
sta View_Future, X
tax
lda ActorTransparent, X
cmp #TRUE
bne end_loop_ray
; loop if tiles are left in the ray
ldx NB_TILES_IN_RAY_LEFT

View File

@ -16,10 +16,11 @@
.include "world/world.inc"
.include "actors/actors.inc"
.include "io/gr.inc"
.include "memory.inc"
.include "math.inc"
.include "monitor.inc"
.include "io/gr.inc"
; inits display of map
.export Display_Map_Init
@ -201,11 +202,12 @@ quit:
rts
.import World
.define SRC_LINE_UP ZERO_7_1
.define SRC_LINE_UP ZERO_7_1
.define SRC_LINE_DOWN ZERO_8_1
.define SRC_OFFSET ZERO_5_5
.define DST_GR1 ZERO_5_5
.define CPT_FILL ZERO_5_4
.define SRC_OFFSET ZERO_5_5
.define DST_GR1 ZERO_5_5
.define CPT_FILL ZERO_5_4
.define TMP ZERO_9_10
Addr_GR1: ; 3 address blocks to fill GR1 (address -1), stored in reversed endianess.
.word $4F04, $2704, $FF03
@ -229,7 +231,7 @@ Addr_GR1: ; 3 address blocks to fill GR1 (address -1), stored in reversed endian
ld_src:
; compute offset
stx ZERO_5_4
stx TMP
sty FAC1
lda #WIDTH_WORLD
sta FAC2
@ -237,7 +239,7 @@ ld_src:
sta SRC_OFFSET+1
txa
clc
adc ZERO_5_4
adc TMP
sta SRC_OFFSET
lda SRC_OFFSET+1
adc #0
@ -277,11 +279,22 @@ copy_8x2_lines: ; call 3 times to fill the screen
ldy #DBG_DISP_WIDTH
copy_2_lines:
lda (SRC_LINE_DOWN),Y
cmp #eACTORTYPES::FIRST_DYNAMIC
bcc keep_color_1
lda #$F ; white
keep_color_1:
asl
asl
asl
asl
ora (SRC_LINE_UP),Y
asl
sta TMP
lda (SRC_LINE_UP),Y
cmp #eACTORTYPES::FIRST_DYNAMIC
bcc keep_color_2
lda #$F ; white
keep_color_2:
and #$F
ora TMP
sta (DST_GR1), Y
dey
bne copy_2_lines

View File

@ -1,27 +1,29 @@
# Configuration:
# APPLESOFT required
# HGR1 & HGR2 segment reserved
# HGR1 & HGR2 memory reserved
# CODE2, RODATA and DATA segment are loaded contiguously in the main memory
# but will be run from MAIN2 memory. The program has to do the relocation.
FEATURES {
STARTADDRESS: default = $0800;
STARTADDRESS: default = $0803;
}
SYMBOLS {
__EXEHDR__: type = import;
__FILETYPE__: type = weak, value = $0006; # ProDOS file type
}
MEMORY {
ZP: file = "", start = $0000, size = $00FF;
HEADER: file = %O, start = %S - 4, size = $0004;
MAIN: file = %O, define = yes, start = %S, size = $2000 - %S;
HGR: file = "", define = no, start = $2000, size = $4000;
CODE2: file = %O, define = yes, start = $6000, size = $100;
DATA: file = %O, define = yes, start = __CODE2_LAST__,size = $3000;
BSSMEM: file = "", define = no, start = __DATA_LAST__, size = $9600 - __DATA_LAST__;
ZP: file = "", start = $0000, size = $00FF;
HEADER: file = %O, start = %S - $3A, size = $003A;
HGR: file = "", define = yes, start = $2000, size = $4000;
MAIN2: file = "", define = yes, start = $6000, size = $3000;
BSSMEM: file = "", define = yes, start = __MAIN2_LAST__, size = $BF00 - __BSSMEM_START__;
MAIN: file = %O, define = yes, start = %S, size = __BSSMEM_START__ - %S - __HGR_SIZE__;
}
SEGMENTS {
ZEROPAGE: load = ZP, type = zp, optional = yes;
EXEHDR: load = HEADER, type = ro;
CODE: load = MAIN, type = rw;
CODE2: load = CODE2, type = rw, optional = yes;
RODATA: load = DATA, type = ro, optional = yes, align = $100;
DATA: load = DATA, type = rw, optional = yes, align = $100;
BSS: load = BSSMEM, type = bss, optional = yes, define = yes, align = $100;
ZEROPAGE: load = ZP, type = zp, optional = no;
EXEHDR: load = HEADER, type = ro;
CODE: load = MAIN, type = rw, define = yes;
CODE2: load = MAIN, run = MAIN2, type = rw, define = yes;
RODATA: load = MAIN, run = MAIN2, type = ro, define = yes, align = $100;
DATA: load = MAIN, run = MAIN2, type = rw, define = yes, align = $100;
BSS: load = BSSMEM, type = bss, define = yes, align = $100;
}

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/actors.inc"
.include "world/level.inc"
.include "world/world.inc"
.include "display.inc"
@ -34,23 +34,32 @@
.import player_move_iny
.import player_move_dex
.import player_move_dey
.import Player_XY
.import ActorPositions
; world
.import world_set_player
; actors
.import ActorPositions
; ************
.include "builder/builder.inc"
.import world_init
.import player_init
.import view_init
.import Actors_Init
; ************
.define KEY_UP $C9
.define KEY_LEFT $CA
.define KEY_DOWN $CB
.define KEY_RIGHT $CC
.define TAB $89
.define KEY_UP_UPP $C9 ; 'I'
.define KEY_UP_LOW $E9 ; 'i'
.define KEY_LEFT_UPP $CA ; 'J'
.define KEY_LEFT_LOW $EA ; 'j'
.define KEY_DOWN_UPP $CB ; 'K'
.define KEY_DOWN_LOW $EB ; 'k'
.define KEY_RIGHT_UPP $CC ; 'L'
.define KEY_RIGHT_LOW $EC ; 'l'
.define TAB $89 ; '\t'
.define Player_XY ActorPositions + eACTORTYPES::PLAYER
.CODE
@ -63,24 +72,21 @@
game_loop:
jsr levels_init
lda #0
sta NextLevel
jsr Actors_Init
level_loop:
jsr level_enter ; Uses NextLevel as level number
; *****************
; jsr Build_Level
jsr Display_Map_Init
; ldx Rooms+2 ; Rooms[0].x
; ldy Rooms+3 ; Rooms[0].y
; jsr player_init
; *****************
jsr Display_Map_Init
ldx Player_XY
ldy Player_XY + 1
jsr world_init
jsr view_init
; *****************
ldx Player_XY
ldy Player_XY+1
@ -97,7 +103,7 @@ game_loop:
jsr key_action
lda ExitLevel
cmp TRUE
cmp #TRUE
bne kbd_loop
jsr level_exit
@ -108,16 +114,29 @@ game_loop:
; action on key pressed
key_action:
cmp #KEY_UP
cmp #KEY_UP_UPP
beq move_up
cmp #KEY_RIGHT
cmp #KEY_UP_LOW
beq move_up
cmp #KEY_RIGHT_UPP
beq move_right
cmp #KEY_DOWN
cmp #KEY_RIGHT_LOW
beq move_right
cmp #KEY_DOWN_UPP
beq move_down
cmp #KEY_LEFT
cmp #KEY_DOWN_LOW
beq move_down
cmp #KEY_LEFT_UPP
beq move_left
cmp #KEY_LEFT_LOW
beq move_left
cmp #TAB
beq display_map
rts
move_up:
@ -125,28 +144,24 @@ move_up:
ldy Player_XY+1
dey
jsr player_move
; jsr player_move_dey
jmp end_action_move
move_right:
ldx Player_XY
ldy Player_XY+1
inx
jsr player_move
; jsr player_move_inx
jmp end_action_move
move_down:
ldx Player_XY
ldy Player_XY+1
iny
jsr player_move
; jsr player_move_iny
jmp end_action_move
move_left:
ldx Player_XY
ldy Player_XY+1
dex
jsr player_move
; jsr player_move_dex
jmp end_action_move
end_action_move: ; update player/view coordinates and refresh the display

481
src/io/files.asm Normal file
View File

@ -0,0 +1,481 @@
; Copyright (C) 2021 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/>.
; TODO a lot of code space can be spared by factorizing ReadState and Write state. Almos the same code
.include "../actors/actors.inc"
.include "../world/level.inc"
.include "../world/world.inc"
.include "../common.inc"
.include "../memory.inc"
.include "../math.inc"
.import World
.import ActorsInLevel
.import LevelIsBuilt
.import PlayerTile
.import Tile_player_standing_actor
; data
; TODO : should remain private!!
.export Str_FileLevelConfs
.export Str_FileLevelsActors
.export Param_FileOpen
.export Param_FileOffset
.export Param_FilesReadWrite
.export File_Buffer
; functions
.export ReadFile
.export LoadState
.export SaveState
.export ResetIsBuilt
.export LoadCurrentLevel
.define TO_PATCH 0
; reserve 1024 bytes for MLI file operations in the upper part of HGR2
File_Buffer := $5C00
.RODATA
Str_FileLevelConfs:
.byte $19, "/PRODOS.2.4.2/LEVELS.CONF" ; Pascal string
Str_FileLevelsActors:
.byte $19, "/PRODOS.2.4.2/LEVELS.ACTS" ; Pascal string
Str_FileStates:
.byte $14, "/PRODOS.2.4.2/STATES" ; Pascal string
.BSS
Lvl_Nr: .res 1
.define MIN_READ_SIZE 256
ReadWriteBuffer: .res MIN_READ_SIZE
.DATA
Param_FileOpen:
.byte $3 ; in - nb params
.addr TO_PATCH ; in - char* filepath
.addr File_Buffer ; in - char* workbuffer
Handle_File:
.byte $0 ; out - handle on the file
Param_FileOffset:
.byte $2 ; in - nb params
.byte TO_PATCH ; in - handle on the file
.byte TO_PATCH, TO_PATCH, 0 ; in - Offset
Param_FilesReadWrite:
.byte $4 ; in - nb params
.byte TO_PATCH ; in - handle on the file
.addr TO_PATCH ; in - out buffer
.word TO_PATCH ; in - max nb bytes to WRITE/READ
.word $0000 ; out - nb bytes write/read
Param_FileClose:
.byte $1 ; in - nb params
.byte TO_PATCH ; in - handle on the file
.CODE
; TODO handle errors
ReadFile:
; Open the file
jsr $BF00 ; call MLI
.byte $C8 ; Open
.addr Param_FileOpen
; Set read position
lda Handle_File
sta Param_FileOffset+1
jsr $BF00 ; call MLI
.byte $CE ; Set Mark
.addr Param_FileOffset
; Read the file
lda Handle_File
sta Param_FilesReadWrite+1
jsr $BF00 ; call MLI
.byte $CA ; read
.addr Param_FilesReadWrite
; Close the file
lda Handle_File
sta Param_FileClose+1
jsr $BF00 ; call MLI
.byte $CC ; Close
.addr Param_FileClose
rts
.define READ_DST ZERO_2_4 ; 2 bytes
; @brief Offset in A:X (little endian)
; HandleFile must have been set by opening the file
_SetOffset:
sta Param_FileOffset+2
stx Param_FileOffset+3
lda Handle_File
sta Param_FileOffset+1
jsr $BF00 ; call MLI
.byte $CE ; Set Mark
.addr Param_FileOffset
rts
; @brief Size in in A:X (little endian)
; Destination ptr in READ_DST: cannot be locate in ZERO PAGE!!!
; HandleFile must have been set by opening the file
_Read:
; Read the file
sta Param_FilesReadWrite+4
stx Param_FilesReadWrite+5
lda Handle_File
sta Param_FilesReadWrite+1
lda READ_DST
sta Param_FilesReadWrite+2
lda READ_DST+1
sta Param_FilesReadWrite+3
jsr $BF00 ; call MLI
.byte $CA ; read
.addr Param_FilesReadWrite
rts
; @param LevelNr in A
; @return isBuilt in A
; modifies ZERO_2_3, ZERO_2_4, ZERO_2_5
.define LVLS_HEADER_SIZE 4
.define LVL_HEADER_SIZE 3
.define OFFSET Param_FileOffset+2
; compute offset and sets file position
_FindLevelLayout:
; Compute the level state offset in file
ldy #(LVLS_HEADER_SIZE + 2 + LVL_HEADER_SIZE) ; +2: current lvl + nb lvls
sty OFFSET
lda #0
sta OFFSET+1
lda Lvl_Nr
tax
cpx #0
beq end_acc_offset_lvl
acc_offset_lvl:
ADD16 OFFSET, #<(HEIGHT_WORLD * WIDTH_WORLD), #>(HEIGHT_WORLD * WIDTH_WORLD)
ADD16 OFFSET, #(LVL_HEADER_SIZE + 2), #0 ; +2: visited + tile
dex
bne acc_offset_lvl
end_acc_offset_lvl:
; Set read position
lda OFFSET
ldx OFFSET+1
jsr _SetOffset
rts
.define ACTSS_HEADER_SIZE 4;
.define ACT_HEADER_SIZE 3;
_FindLevelActors:
; Compute offset
lda #(LVLS_HEADER_SIZE + 2)
sta OFFSET
lda #0
sta OFFSET+1
ldx NbLevels
acc_offset_lvls:
ADD16 OFFSET, #<(HEIGHT_WORLD * WIDTH_WORLD), #>(HEIGHT_WORLD * WIDTH_WORLD)
ADD16 OFFSET, #(LVL_HEADER_SIZE + 2), #0 ; +2: visited + tile
dex
bne acc_offset_lvls
ADD16 OFFSET, #(ACTSS_HEADER_SIZE + ACT_HEADER_SIZE), #0
ldx Lvl_Nr
cpx #0
beq end_acc_offset_actors
acc_offset_actors:
ADD16 OFFSET, #<(ACT_HEADER_SIZE + SIZEOF_ACTORS_T), #>(ACT_HEADER_SIZE + SIZEOF_ACTORS_T)
dex
bne acc_offset_actors
end_acc_offset_actors:
; Set read position
lda OFFSET
ldx OFFSET+1
jsr _SetOffset
rts
; @param Level NR in A
LoadState:
sta Lvl_Nr
; Open the file
lda #<Str_FileStates
sta Param_FileOpen+1
lda #>Str_FileStates
sta Param_FileOpen+2
jsr $BF00 ; call MLI
.byte $C8 ; Open
.addr Param_FileOpen
; save the new current level
lda #(LVLS_HEADER_SIZE)
ldx #0
jsr _SetOffset ; current lvl
lda #<Lvl_Nr
sta READ_DST
lda #>Lvl_Nr
sta READ_DST+1
lda #1
ldx #0
jsr _Write
lda Lvl_Nr
jsr _FindLevelLayout ; compute offset and sets file read position
lda #<ReadWriteBuffer
sta READ_DST
lda #>ReadWriteBuffer
sta READ_DST+1
lda #<MIN_READ_SIZE
ldx #>MIN_READ_SIZE
jsr _Read
lda ReadWriteBuffer
sta LevelIsBuilt
lda ReadWriteBuffer+1
sta Tile_player_standing_actor
lda LevelIsBuilt
cmp #FALSE
beq LoadState_end
; Read the level's layout
; Set read position
ADD16 OFFSET, #2, #0 ; offset past "visited" & "tile"
lda OFFSET
ldx OFFSET+1
jsr _SetOffset
; Read the file
lda #<World
sta READ_DST
lda #>World
sta READ_DST+1
lda #<(HEIGHT_WORLD * WIDTH_WORLD)
ldx #>(HEIGHT_WORLD * WIDTH_WORLD)
jsr _Read
; Read level actors state
jsr _FindLevelActors ; compute offset and sets file read position
; Read the file
lda #<ActorsInLevel
sta READ_DST
lda #>ActorsInLevel
sta READ_DST+1
lda #<(SIZEOF_ACTORS_T)
ldx #>(SIZEOF_ACTORS_T)
jsr _Read
LoadState_end:
; Close the file
lda Handle_File
sta Param_FileClose+1
jsr $BF00 ; call MLI
.byte $CC ; Close
.addr Param_FileClose
rts
.define WRITE_DST ZERO_2_4 ; 2 bytes
; @brief Size in in A:X (little endian)
; Destination ptr in WRITE_DST: cannot be locate in ZERO PAGE!!!
; HandleFile must have been set by opening the file
_Write:
; Wr the file
sta Param_FilesReadWrite+4
stx Param_FilesReadWrite+5
lda Handle_File
sta Param_FilesReadWrite+1
lda WRITE_DST
sta Param_FilesReadWrite+2
lda WRITE_DST+1
sta Param_FilesReadWrite+3
jsr $BF00 ; call MLI
.byte $CB ; write
.addr Param_FilesReadWrite
rts
; @param Level NR in A
SaveState:
sta Lvl_Nr
; Open the file
lda #<Str_FileStates
sta Param_FileOpen+1
lda #>Str_FileStates
sta Param_FileOpen+2
jsr $BF00 ; call MLI
.byte $C8 ; Open
.addr Param_FileOpen
lda Lvl_Nr
jsr _FindLevelLayout ; compute offset and sets file write position
; Write the file
lda #TRUE
sta ReadWriteBuffer
lda Tile_player_standing_actor
sta ReadWriteBuffer+1
lda #<ReadWriteBuffer
sta WRITE_DST
lda #>ReadWriteBuffer
sta WRITE_DST+1
lda #<MIN_READ_SIZE
ldx #>MIN_READ_SIZE
jsr _Write
; Write the level's layout
; Set write position
ADD16 OFFSET, #2, #0 ; offset past "visited" & "tile"
lda OFFSET
ldx OFFSET+1
jsr _SetOffset
; Write the file
lda #<World
sta WRITE_DST
lda #>World
sta WRITE_DST+1
lda #<(HEIGHT_WORLD * WIDTH_WORLD)
ldx #>(HEIGHT_WORLD * WIDTH_WORLD)
jsr _Write
; Write level actors state
jsr _FindLevelActors ; compute offset and sets file write position
; Write the file
lda #<ActorsInLevel
sta WRITE_DST
lda #>ActorsInLevel
sta WRITE_DST+1
lda #<(SIZEOF_ACTORS_T)
ldx #>(SIZEOF_ACTORS_T)
jsr _Write
; Close the file
lda Handle_File
sta Param_FileClose+1
jsr $BF00 ; call MLI
.byte $CC ; Close
.addr Param_FileClose
rts
; @param LevelNr in A
ResetIsBuilt:
sta Lvl_Nr
; Open the file
lda #<Str_FileStates
sta Param_FileOpen+1
lda #>Str_FileStates
sta Param_FileOpen+2
jsr $BF00 ; call MLI
.byte $C8 ; Open
.addr Param_FileOpen
for_each_lvl:
dec Lvl_Nr
jsr _FindLevelLayout ; compute offset and sets file write position
inc Lvl_Nr
lda #FALSE
sta ReadWriteBuffer
lda #<ReadWriteBuffer
sta WRITE_DST
lda #>ReadWriteBuffer
sta WRITE_DST+1
lda #<MIN_READ_SIZE
ldx #>MIN_READ_SIZE
jsr _Write
dec Lvl_Nr
bne for_each_lvl
; Close the file
lda Handle_File
sta Param_FileClose+1
jsr $BF00 ; call MLI
.byte $CC ; Close
.addr Param_FileClose
rts
LoadCurrentLevel:
; Open the file
lda #<Str_FileStates
sta Param_FileOpen+1
lda #>Str_FileStates
sta Param_FileOpen+2
jsr $BF00 ; call MLI
.byte $C8 ; Open
.addr Param_FileOpen
; load the current level
lda #(LVLS_HEADER_SIZE)
ldx #0
jsr _SetOffset ; current lvl
lda #<ReadWriteBuffer
sta READ_DST
lda #>ReadWriteBuffer
sta READ_DST+1
lda #<MIN_READ_SIZE
ldx #>MIN_READ_SIZE
jsr _Read
lda ReadWriteBuffer
sta NextLevel
; Close the file
lda Handle_File
sta Param_FileClose+1
jsr $BF00 ; call MLI
.byte $CC ; Close
.addr Param_FileClose
rts

30
src/io/files.inc Normal file
View File

@ -0,0 +1,30 @@
; Copyright (C) 2021 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/>.
; data
; TODO : should remain private!!
.import Str_FileLevelConfs
.import Str_FileLevelsActors
.import Param_FileOpen
.import Param_FileOffset
.import Param_FilesReadWrite
; functions
.import ReadFile
.import LoadState
.import SaveState
.import ResetIsBuilt
.import LoadCurrentLevel

View File

@ -151,7 +151,7 @@ Cin_Str:
sta TXT1_LINE23, X ; erase the cursor
lda #0
sta CIN_STR, X
rts
delete:

View File

@ -35,17 +35,15 @@ GR_TITLE_09 : .byte $0,$0,$99,$0,$0,$0,$0,$0,$0,$0,$0,$0,$88,$0,$88,$0,$0,$0,$0
GR_TITLE_10 : .byte $0,$0,$99,$99,$99,$99,$99,$0,$88,$0,$0,$0,$88,$0,$88,$0,$0,$0,$0,$0,$88,$0,$0,$0,$0,$88,$0,$88,$0,$0,$0,$0,$0,$0,$99,$99,$99,$99,$99,$0
GR_TITLE_11 : .byte $0,$0,$99,$99,$99,$99,$99,$0,$88,$88,$88,$88,$0,$0,$0,$88,$88,$88,$88,$0,$88,$0,$0,$0,$0,$88,$0,$88,$0,$0,$0,$0,$0,$0,$99,$99,$99,$99,$99,$0
GR_TITLE_12 : .byte $0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0
GR_TITLE_13 : .byte $0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0
GR_TITLE_14 : .byte $0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0
GR_TITLE_15 : .byte $0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$55,$55,$0,$0,$55,$55,$55,$0,$0,$55,$55,$0,$0,$0,$0,$55,$55,$55,$0,$55,$55,$55,$0,$55,$55,$0,$55,$55,$55,$0
GR_TITLE_16 : .byte $0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$55,$0,$55,$0,$55,$0,$0,$0,$55,$0,$0,$0,$0,$0,$0,$0,$0,$55,$0,$55,$0,$55,$0,$0,$55,$0,$55,$0,$55,$0
GR_TITLE_17 : .byte $0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$55,$55,$0,$0,$55,$0,$55,$0,$55,$0,$0,$0,$0,$0,$0,$55,$0,$0,$0,$55,$0,$55,$0,$0,$55,$0,$55,$55,$55,$0
GR_TITLE_18 : .byte $0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$55,$0,$55,$0,$55,$55,$55,$0,$0,$55,$55,$0,$0,$0,$0,$55,$55,$55,$0,$55,$55,$55,$0,$0,$55,$0,$0,$0,$55,$0
GR_TITLE_13 : .byte $0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0
GR_TITLE_14 : .byte $0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$55,$55,$55,$55,$0,$0,$55,$55,$55,$55,$55,$55,$0,$55,$55,$55,$55,$55,$55,$0,$55,$55,$55,$55,$55,$0,$0,$0
GR_TITLE_15 : .byte $0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$55,$0,$0,$0,$0,$55,$0,$0,$0,$0,$0,$0,$55,$0,$55,$0,$0,$0,$0,$0,$0,$55,$0,$0,$0,$0,$55,$0,$0
GR_TITLE_16 : .byte $0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$55,$55,$55,$55,$55,$55,$0,$55,$55,$55,$55,$55,$55,$0,$55,$55,$55,$55,$0,$0,$0,$55,$55,$55,$55,$55,$0,$0,$0
GR_TITLE_17 : .byte $0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$55,$0,$0,$0,$0,$55,$0,$55,$0,$0,$0,$0,$0,$0,$55,$0,$0,$0,$0,$0,$0,$55,$0,$0,$0,$0,$0,$0,$0
GR_TITLE_18 : .byte $0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$55,$0,$0,$0,$0,$55,$0,$55,$55,$55,$55,$55,$55,$0,$55,$0,$0,$0,$0,$0,$0,$55,$0,$0,$0,$0,$0,$0,$0
GR_TITLE_19 : .byte $0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0
STR_NAME: ASCIIZ "WHAT'S YOUR NAME, ADVENTURER?"
.CODE
@ -102,9 +100,10 @@ Title_Scr_Addr:
.word GR_TITLE_11, GR_TITLE_12, GR_TITLE_13, GR_TITLE_14, GR_TITLE_15, GR_TITLE_16, GR_TITLE_17, GR_TITLE_18, GR_TITLE_19
.CODE
; @brief Displays's the title screen
; @brief Displays's the title screen and main game menu
Title:
; Title Screen
jsr Clear_Gr1
jsr ClearTxt
@ -133,11 +132,4 @@ Title:
cpy #$26
bne loop_scrolling
lda #>STR_NAME
ldx #<STR_NAME
jsr Print
jsr Cin_Str
rts

View File

@ -20,49 +20,83 @@
.include "display_map.inc"
.include "builder/builder.inc"
.include "io/textio.inc"
.include "io/files.inc"
.export _main
; functions
.import world_init
.import player_init
.import view_init
.import game_loop
.import Title
.import level_reset_states
.import __MAIN_LAST__
.import __DATA_START__
.import memcpy
.import memset
.import meminit
; data
.import __CODE2_LOAD__
.import __CODE2_RUN__
.import __CODE2_SIZE__
.import __RODATA_LOAD__
.import __RODATA_RUN__
.import __RODATA_SIZE__
.import __DATA_LOAD__
.import __DATA_RUN__
.import __DATA_SIZE__
.import __CODE2_START__
.import __CODE2_LAST__
.DATA
STR_EMPTY: ASCIIZ " "
STR_NEWGAME: ASCIIZ "(N)EW GAME"
STR_JOURNEY: ASCIIZ "(J)OURNEY ONWARD"
STR_NAME: ASCIIZ "WHAT'S YOUR NAME, ADVENTURER?"
.CODE
_main:
lda #<__MAIN_LAST__
; jsr meminit // Uncomment to zero memory, for debug
; Relocations after the HGR "hole"
; relocating code
lda #<__CODE2_LOAD__
sta FROM
lda #>__MAIN_LAST__
lda #>__CODE2_LOAD__
sta FROM+1
lda #<__CODE2_START__
lda #<__CODE2_RUN__
sta TO
lda #>__CODE2_START__
lda #>__CODE2_RUN__
sta TO+1
lda #<(__CODE2_LAST__ - __CODE2_START__)
lda #<__CODE2_SIZE__
sta SIZEL
lda #>(__CODE2_LAST__ - __CODE2_START__)
lda #>__CODE2_SIZE__
sta SIZEH
jsr memcpy
; Relocate DATA from its freshly loaded location to __DATA_START__
; computing DATA actual starting address
lda #<(__MAIN_LAST__ + __CODE2_LAST__ - __CODE2_START__)
; relocating RODATA
lda #<__RODATA_LOAD__
sta FROM
lda #>(__MAIN_LAST__ + __CODE2_LAST__ - __CODE2_START__)
lda #>__RODATA_LOAD__
sta FROM+1
lda #<__DATA_START__
lda #<__RODATA_RUN__
sta TO
lda #>__DATA_START__
lda #>__RODATA_RUN__
sta TO+1
lda #<__RODATA_SIZE__
sta SIZEL
lda #>__RODATA_SIZE__
sta SIZEH
jsr memcpy
; relocating DATA
lda #<__DATA_LOAD__
sta FROM
lda #>__DATA_LOAD__
sta FROM+1
lda #<__DATA_RUN__
sta TO
lda #>__DATA_RUN__
sta TO+1
lda #<__DATA_SIZE__
sta SIZEL
@ -70,20 +104,71 @@ _main:
sta SIZEH
jsr memcpy
jsr Title ; will init the seed
jsr _StartMenu ; will init the seed
; overwrite the seed to debug
;lda #$0
;sta SEED0
;lda #$0
;sta SEED1
;lda #$0
;sta SEED2
;lda #$0
;sta SEED3
; lda #$0
; sta SEED0
; lda #$0
; sta SEED1
; lda #$0
; sta SEED2
; lda #$0
; sta SEED3
jsr Random8_Init
; Run
jsr game_loop
rts
; @brief Starting game menu
_StartMenu:
; Scrolling Title
jsr Title
; New game or continue
lda #>STR_NEWGAME
ldx #<STR_NEWGAME
jsr Print
lda #>STR_JOURNEY
ldx #<STR_JOURNEY
jsr Print
kbd_wait:
lda KEYBD
bpl kbd_wait
sta KEYBD_STROBE
cmp #($4E + $80) ; 'N'
beq new_game
cmp #($6E + $80) ; 'n'
beq new_game
cmp #($4A + $80) ; 'J'
beq journey_onward
cmp #($6A + $80) ; 'j'
beq journey_onward
bne kbd_wait
journey_onward:
jsr LoadCurrentLevel
jmp start_menu_end
new_game:
; Ask for name
lda #>STR_NAME
ldx #<STR_NAME
jsr Print
jsr Cin_Str ; Init seed
; delete progress
jsr level_reset_states
start_menu_end:
rts

View File

@ -32,13 +32,13 @@
.endmacro
.macro ADD16 addr, cste
.macro ADD16 addr, csteL, csteH
clc
lda addr
adc cste
adc csteL
sta addr
lda addr+1
adc #0
adc csteH
sta addr+1
.endmacro

View File

@ -14,27 +14,13 @@
; You should have received a copy of the GNU General Public License
; along with this program. If not, see <http://www.gnu.org/licenses/>.
; Must be the same as in memory.inc !!
.define ZERO_2_1 $19
.define ZERO_2_3 $1B
.define ZERO_8_1 $D6
.define ZERO_8_2 $D7
.define FROM ZERO_2_1
.define TO ZERO_2_3
.define SIZEH ZERO_8_1
.define SIZEL ZERO_8_2
.include "memory.inc"
.export memcpy
.export TXT1_LINES
.export memset
.export meminit
.DATA
TXT1_LINES:
.word $400, $480, $500, $580, $600, $680, $700, $780, $428, $4A8, $528, $5A8, $628, $6A8
.word $728, $7A8, $450, $4D0, $550, $5D0, $650, $6D0, $750, $7D0
.CODE
; http://www.6502.org/source/general/memory_move.html
@ -69,4 +55,84 @@ MU3: DEY
DEC TO+1
DEX
BNE MU1
RTS
RTS
; Sets a block of memory to the provided value
;
; A = value to set
; TO = memory to be set starting address
; SIZE = number of bytes to set. Max value: $FEFF
;
; !!! TO and SIZE are overwritten !!
memset:
cmp SIZEH
beq memset_remain
memset_loop_hi:
ldy #$FF
memset_loop_low:
sta (TO),Y
dey
bne memset_loop_low
sta (TO),Y
inc TO+1 ; next 256 byte block
dec SIZEH
bne memset_loop_hi
memset_remain:
ldy SIZEL
cpy #0
beq memset_end
memset_loop_remain:
sta (TO),Y
dey
bne memset_loop_remain
memset_end:
rts
; DEBUG: zeros the useful memory locations
meminit:
lda #0
sta TO
ldx #$60
stx TO+1
ldx #$FF
stx SIZEL
ldx #$05
stx SIZEH
jsr memset
lda #0
sta ZERO_2_1
sta ZERO_2_2
sta ZERO_2_3
sta ZERO_2_4
sta ZERO_2_5
sta ZERO_2_6
sta ZERO_3
sta ZERO_4_1
sta ZERO_4_2
sta ZERO_4_3
sta ZERO_4_4
sta ZERO_4_5
sta ZERO_5_1
sta ZERO_5_2
sta ZERO_5_3
sta ZERO_5_4
sta ZERO_5_5
sta ZERO_5_6
sta ZERO_7_1
sta ZERO_7_2
sta ZERO_8_1
sta ZERO_8_2
sta ZERO_9_1
sta ZERO_9_2
sta ZERO_9_3
sta ZERO_9_4
sta ZERO_9_5
sta ZERO_9_6
sta ZERO_9_7
sta ZERO_9_8
sta ZERO_9_9
sta ZERO_9_10
rts

View File

@ -110,9 +110,8 @@
; *********** CUSTOM ROUTINES *********
.define FROM ZERO_2_1 ; 2 bytes
.define TO ZERO_2_3 ; 2 bytes
.define SIZEH ZERO_8_1
.define SIZEL ZERO_8_2
.import memcpy
.define SIZEH ZERO_8_2
.define SIZEL ZERO_8_1
; ************ MACROS ***********

View File

@ -20,6 +20,7 @@
.include "monitor.inc"
.include "io/textio.inc"
.include "world/world.inc"
.include "actors/actors.inc"
; init the player's structures
@ -34,39 +35,26 @@
; They may be unmodified ;)
; DESTROY A, X, Y, ZERO_2_1, ZERO_2_2
; Increments Player's X position
.export player_move_inx
; Increments Player's Y position
.export player_move_iny
; Decrements Player's X position
.export player_move_dex
; Decrements Player's Y position
.export player_move_dey
; Player coordinates in the maze ([0:255], [0:255])
.export Player_XY
.import Compute_Maze_Addr
.import Reactions_lsb
.import Reactions_msb
.import ActorTypes
.import ActorPositions
.BSS
.define TO_BE_PATCHED 0
.define Player_XY ActorPositions + eACTORTYPES::PLAYER
Player_XY: .res 2
.DATA
STR_HIT_WALL: ASCIIZ "YOU HIT A WALL"
.CODE
STR_GO_UP: ASCIIZ "YOU GO NORTH"
STR_GO_RIGHT: ASCIIZ "YOU GO EAST"
STR_GO_DOWN: ASCIIZ "YOU GO SOUTH"
STR_GO_LEFT: ASCIIZ "YOU GO WEST"
STR_HIT_WALL: ASCIIZ "YOU HIT A WALL"
; @brief Player initial coords
; @param X player's x
; @param Y player's y
; @param Y player's y
player_init:
stx Player_XY
sty Player_XY+1
@ -80,26 +68,30 @@ player_init:
player_move:
stx NEW_PLAYER_XY
sty NEW_PLAYER_XY+1
sty NEW_PLAYER_XY+1
jsr Compute_Maze_Addr
; get the actor
; get the actor id
stx ADDR_IN_MAZE
sta ADDR_IN_MAZE+1
ldy #0
lda (ADDR_IN_MAZE), Y
tax
; get the actor's type
lda ActorTypes, X
tay
; get the reaction address
lda Reactions_lsb, X
lda Reactions_lsb, Y
sta FUNC_REACTION + 1
lda Reactions_msb, X
lda Reactions_msb, Y
sta FUNC_REACTION+2
FUNC_REACTION : jsr 0
FUNC_REACTION : jsr TO_BE_PATCHED ; actord id in Y
cmp TRUE
cmp #TRUE
bne end_player_move
ldx NEW_PLAYER_XY
stx Player_XY
@ -113,49 +105,6 @@ end_player_move:
rts
; !!! ALL THE MOVE FUNCTION HAVE TO BE GROUPED TOGHETHER
; AS THERE IS A COMMON RETURN POINT TO WHICH THEY BRANHC (KEEP PC's DISTANCE < 127) !!!
player_move_inx:
; test that x+1 is "WALKABLE"
ldx Player_XY
ldy Player_XY+1
jsr Compute_Maze_Addr ; we get the adress for x,y then we increment x
stx ADDR_IN_MAZE
sta ADDR_IN_MAZE+1
ldy #1 ; will look at x+1
lda #ACTORS::WALKABLE
cmp (ADDR_IN_MAZE), Y
bcc hit_wall ; carry cleared if A is strictly the lesser --> not walkable
ldx Player_XY
inx
stx Player_XY ; walkable
PRINT STR_GO_RIGHT
jmp return_from_player_move
player_move_dex:
; test that x-1 is "WALKABLE"
ldx Player_XY
dex
ldy Player_XY+1
jsr Compute_Maze_Addr ; we get the adress for x-1
stx ADDR_IN_MAZE
sta ADDR_IN_MAZE+1
ldy #0 ; will look at x-1
lda #ACTORS::WALKABLE
cmp (ADDR_IN_MAZE), Y
bcc hit_wall ; carry cleared if A is strictly the lesser --> not walkable
ldx Player_XY
dex
stx Player_XY ; walkable
PRINT STR_GO_LEFT
jmp return_from_player_move
; Common code to return from the moves.
; Moves BRANCH to here
return_from_player_move:
@ -169,47 +118,3 @@ hit_wall:
PRINT STR_HIT_WALL
jmp return_from_player_move
player_move_iny:
; test that y+1 is "WALKABLE"
ldy Player_XY+1
ldx Player_XY
iny
jsr Compute_Maze_Addr ; we get the adress for x,y+1
stx ADDR_IN_MAZE
sta ADDR_IN_MAZE+1
ldy #0
lda #ACTORS::WALKABLE
cmp (ADDR_IN_MAZE), Y
bcc hit_wall ; carry cleared if A is strictly the lesser --> not walkable
ldy Player_XY+1 ; walkable
iny
sty Player_XY+1
PRINT STR_GO_DOWN
jmp return_from_player_move
player_move_dey:
; test that y-1 is "WALKABLE"
ldy Player_XY+1
ldx Player_XY
dey
jsr Compute_Maze_Addr ; we get the adress for x,y-1
stx ADDR_IN_MAZE
sta ADDR_IN_MAZE+1
ldy #0
lda #ACTORS::WALKABLE
cmp (ADDR_IN_MAZE), Y
bcc hit_wall ; carry cleared if A is strictly the lesser --> not walkable
ldy Player_XY+1 ; walkable
dey
sty Player_XY+1
PRINT STR_GO_UP
bvc return_from_player_move
.undef ADDR_IN_MAZE

View File

@ -106,10 +106,10 @@ FLOOR_4:
.byte $D5, $AA, $D5, $AA
STAIR_DOWN:
.byte $55, $2A, $55, $2A
.byte $01, $AA, $D4, $00
.byte $01, $8A, $D4, $82
.byte $71, $01, $C0, $82
.byte $71, $79, $00, $00
.byte $11, $00, $40, $00
.byte $71, $7F, $7F, $1F
.byte $71, $01, $C5, $82
.byte $71, $79, $80, $8A
.byte $71, $79, $3C, $00
.byte $71, $79, $3C, $1E
.byte $71, $79, $3C, $1E
@ -123,21 +123,21 @@ STAIR_DOWN:
.byte $01, $8A, $95, $A8
STAIR_UP:
.byte $55, $2A, $55, $2A
.byte $71, $7F, $7F, $1F
.byte $71, $79, $D4, $82
.byte $71, $79, $3C, $8A
.byte $71, $79, $3C, $88
.byte $71, $79, $3C, $1E
.byte $71, $79, $3C, $1E
.byte $71, $79, $3C, $1E
.byte $71, $79, $3C, $1E
.byte $71, $79, $3C, $1E
.byte $70, $79, $3C, $1E
.byte $70, $79, $3C, $1E
.byte $70, $79, $3C, $1E
.byte $90, $78, $3C, $1E
.byte $D0, $A8, $3C, $1E
.byte $D0, $A0, $94, $1E
.byte $01, $00, $90, $F8
.byte $01, $AA, $70, $79
.byte $01, $E2, $73, $79
.byte $01, $60, $73, $79
.byte $41, $67, $73, $79
.byte $41, $67, $73, $79
.byte $41, $67, $73, $79
.byte $41, $67, $73, $79
.byte $41, $67, $73, $79
.byte $40, $67, $73, $79
.byte $40, $67, $73, $79
.byte $40, $67, $73, $79
.byte $40, $67, $F3, $A1
.byte $40, $67, $D3, $A8
.byte $C0, $A7, $91, $A8
WALL_1:
.byte 197, 138, 213, 168
.byte 197, 138, 213, 168
@ -172,6 +172,74 @@ WALL_2:
.byte $7F, $7F, $7F, $7F
.byte $7F, $7F, $7F, $7F
.byte $7F, $7F, $7F, $7F
COFFER:
.byte $55, $2A, $55, $2A
.byte $01, $20, $00, $00
.byte $01, $7E, $0F, $00
.byte $41, $67, $3C, $00
.byte $31, $66, $4C, $01
.byte $31, $66, $4C, $01
.byte $31, $66, $4C, $01
.byte $71, $7F, $7F, $01
.byte $31, $C0, $40, $01
.byte $35, $C0, $40, $2B
.byte $B0, $C0, $40, $01
.byte $30, $00, $40, $01
.byte $30, $00, $40, $01
.byte $70, $7F, $7F, $01
.byte $70, $7F, $7F, $01
.byte $10, $00, $40, $00
RAT:
.byte $55, $2A, $55, $2A
.byte $01, $20, $03, $00
.byte $01, $20, $EF, $81
.byte $01, $20, $7C, $1F
.byte $01, $78, $7F, $1F
.byte $01, $7E, $BF, $85
.byte $41, $7F, $0F, $00
.byte $71, $7F, $03, $00
.byte $7D, $7F, $03, $00
.byte $5D, $7F, $57, $2A
.byte $5C, $1F, $43, $00
.byte $5C, $01, $43, $00
.byte $50, $01, $4F, $00
.byte $50, $1F, $40, $00
.byte $10, $00, $40, $00
.byte $10, $00, $40, $00
SERPENT:
.byte $55, $2A, $55, $2A
.byte $01, $20, $03, $00
.byte $01, $60, $0C, $00
.byte $01, $60, $3F, $00
.byte $01, $60, $8B, $80
.byte $01, $60, $A3, $81
.byte $01, $60, $00, $00
.byte $01, $78, $00, $00
.byte $01, $7E, $00, $00
.byte $55, $2F, $55, $2A
.byte $70, $01, $40, $00
.byte $30, $18, $40, $00
.byte $30, $78, $40, $00
.byte $30, $60, $40, $00
.byte $70, $79, $40, $00
.byte $40, $1F, $40, $00
SPIDER:
.byte $55, $2A, $55, $2A
.byte $01, $18, $03, $00
.byte $01, $60, $00, $00
.byte $01, $78, $03, $00
.byte $01, $78, $03, $00
.byte $01, $60, $00, $00
.byte $01, $78, $03, $00
.byte $71, $5F, $7F, $01
.byte $01, $5E, $0F, $00
.byte $75, $5F, $7F, $2B
.byte $10, $56, $0E, $00
.byte $70, $5F, $7F, $01
.byte $10, $58, $43, $00
.byte $50, $7F, $7F, $00
.byte $10, $60, $40, $00
.byte $10, $00, $40, $00
UNKNOWN:
.byte $80, $80, $80, $80
.byte $80, $80, $80, $80
@ -192,8 +260,34 @@ UNKNOWN:
.ALIGN 256
; DON"T FORGET TO UPDATE NB_TILES!!
; Tiles used by ACTORS
; 128 addresses
TILES:
.word PLAYER
.word FLOOR_1, FLOOR_2, FLOOR_3, FLOOR_4, FLOOR_4, FLOOR_4, STAIR_DOWN, STAIR_UP
.word WALL_1, WALL_2, UNKNOWN
; floors
.word FLOOR_1, FLOOR_2, FLOOR_3, FLOOR_4, FLOOR_4, FLOOR_4
; walls
.word WALL_1, WALL_2, WALL_2, WALL_2
; stairs
.word STAIR_DOWN, STAIR_UP
; items
.word COFFER
; monsters
.word RAT, SPIDER, SERPENT
; other
; COMPLETE TO GET THE 128 TILES!!!
.word UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN
.word UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN
.word UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN
.word UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN
.word UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN
.word UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN
.word UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN
.word UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN
.word UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN
.word UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN
.word UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN
.word UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN
.word UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN
.word UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN

View File

@ -1,154 +0,0 @@
; Copyright (C) 2018 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 "world.inc"
.include "tiles.inc"
.include "random.inc"
.include "math.inc"
.include "memory.inc"
.export World
; initializes the world
; DESTROYS A,X,Y, ZERO_2_1, ZERO_2_2, ZERO_2_3
.export world_init
; sets the player's position onto the Maze
; in: X = x coord in the maze
; in: Y = y coord in the maze
; out : X and Y as they where given
; DESTROYS A,X,Y, ZERO_2_1, ZERO_2_2, ZERO_2_4, ZERO_2_5
.export world_set_player
; Computes the adress corresponding to the coordinates in the maze
; in: X = x coord in the maze
; in: Y = y coord in the maze
; out: AX = Address corresponding to (x,y) in the World array
; DESTROYS A,X,Y, ZERO_2_1, ZERO_2_2, ZERO_2_3
.export Compute_Maze_Addr
.define TILE_NR ZERO_2_1
.define COORD_X ZERO_2_1
.define COORD_Y ZERO_2_2
.define OFFSET ZERO_2_2
.BSS
; The tile where the player stands
.struct Tile_player_standing
addr .word ; adress of the location
actor .byte ; actor on the location tile
.endstruct
.CODE
; @param X Player's x
; @param Y Player's y
world_init:
; Saving the first tile on which the player stands
; FIXME player could be standing anywhere on any type of floor
jsr Compute_Maze_Addr
stx Tile_player_standing::addr
sta Tile_player_standing::addr+1
stx ZERO_2_1
sta ZERO_2_1+1
ldy #0
lda (ZERO_2_1), Y
sta Tile_player_standing::actor
rts
; sets the player's position onto the World
world_set_player:
stx ZERO_2_4
sty ZERO_2_5
; restore the previous tile
ldx Tile_player_standing::addr
lda Tile_player_standing::addr+1
stx ZERO_2_1
sta ZERO_2_1+1
ldy #0
lda Tile_player_standing::actor
sta (ZERO_2_1), Y
; save the next tile
ldx ZERO_2_4
ldy ZERO_2_5
jsr Compute_Maze_Addr ; get's player's position address in memory
stx Tile_player_standing::addr
sta Tile_player_standing::addr+1
stx ZERO_2_1
sta ZERO_2_1+1
ldy #0
lda (ZERO_2_1), y
sta Tile_player_standing::actor
; sets the player on the tile
lda #ACTORS::PLAYER
sta (ZERO_2_1), y
; restore the given locations
ldx ZERO_2_4
ldy ZERO_2_5
rts
; Destroys ZERO_2_1, ZERO_2_2, ZERO_2_3 ZERO_7_1 and ZERO_7_2
Compute_Maze_Addr:
stx COORD_X
; offset due to Y coord
sty FAC1
lda #WIDTH_WORLD
sta FAC2
jsr mul8
tay ; high part of the mul
txa ; low part of the mul
; adding offset due to X
clc
adc COORD_X
sta OFFSET
tya
adc #0
sta OFFSET+1
; adding the offset to the address
lda #<World
clc
adc OFFSET
tax ; low part of address to be returned in X
lda #>World
adc OFFSET+1 ; high part of address to be returned in A
rts
.DATA
.align 256
World: .res (WIDTH_WORLD) * (HEIGHT_WORLD)

View File

@ -1,34 +0,0 @@
; The world contains a Maze, filled with Actors
; Actors can be static, such a a floor or a wall,
; dynamic such as a door
; or alive, such as a monster
.define MAXIMUM_WIDTH_MAZE 64 ; must be a power of 2
.define MAXIMUM_HEIGHT_MAZE 64 ; must be a power of 2
.define WIDTH_WORLD 64
.define NEG_WIDTH_WORLD $C0
.define HEIGHT_WORLD 64
.define NEG_HEIGHT_WORLD 64 $C0
.enum ACTORS
PLAYER = 0
FLOOR_1 = 1
FLOOR_2 ; FLOOR BY DEFAULT
FLOOR_3
FLOOR_4
WALKABLE = FLOOR_4 ; Player won't be allowed to go on anything > WALKABLE
NOT_WALKABLE
NOT_TRANSPARENT = NOT_WALKABLE
WALL_1 = NOT_WALKABLE
WALL_2
UNKNOWN
NB_ACTORS
.endenum

View File

@ -17,133 +17,119 @@
.include "../common.inc"
.include "../memory.inc"
.include "../random.inc"
.include "../builder/actors.inc"
.include "../math.inc"
.include "../actors/actors.inc"
.include "../builder/builder.inc"
.include "../io/files.inc"
.include "level_private.inc"
; code
.export levels_init
.export level_enter
.export level_exit
.export level_get_config_offset
.export level_reset_states
; data
.export Levels
.export LevelConfigs
.export NbLevels
.export CurrentLevel
.export NextLevel
.export ExitLevel
.export LevelIsBuilt
.import player_init
.import ActorsInLevel
.import ActorPositions
.import World
.BSS
CurrentLevel: .res 1
NbLevels: .res 1
NextLevel: .res 1
ExitLevel: .res 1
.align 256 ; to be sure it is accessible with an offset
Levels: .res SIZEOF_CONF_LEVEL * NB_LEVELS
LevelIsBuilt: .res 1
.CODE
LevelConfigs: .res 1 + NB_LEVELS * SIZEOF_CONF_LEVEL
.define NR_ACTORS ZERO_4_1
.define NR_LEVELS ZERO_4_2
; TODO Load a configuration file from disk!
.segment "CODE2"
.define ACCUMULATOR ZERO_9_4 ; 2 bytes
; @param LevelNr in X
_Set_Params_LoadSaveLevelActors:
; compute offset in file
lda #0
sta ACCUMULATOR
sta ACCUMULATOR+1
beq end_loop_offset
loop_offset: ; accumulating offsets
clc
lda ACCUMULATOR
adc #<(SIZEOF_ACTORS_T)
sta ACCUMULATOR
lda ACCUMULATOR+1
adc #>(SIZEOF_ACTORS_T)
sta ACCUMULATOR+1
dex
bne loop_offset
end_loop_offset:
; set function parameters
sta Param_FileOffset+3
lda ACCUMULATOR
sta Param_FileOffset+2
lda #<Str_FileLevelsActors
sta Param_FileOpen+1
lda #>Str_FileLevelsActors
sta Param_FileOpen+2
lda #<ActorsInLevel
sta Param_FilesReadWrite+2
lda #>ActorsInLevel
sta Param_FilesReadWrite+3
rts
.define NR_LEVELS ZERO_4_1
levels_init:
ldx #0
ldy #0
lda #NB_LEVELS
; file path
lda #<Str_FileLevelConfs
sta Param_FileOpen+1
lda #>Str_FileLevelConfs
sta Param_FileOpen+2
; read buffer
lda #0
sta Param_FileOffset+2
sta Param_FileOffset+3
sta Param_FileOffset+4
lda #<LevelConfigs
sta Param_FilesReadWrite+2
lda #>LevelConfigs
sta Param_FilesReadWrite+3
lda #<(1 + SIZEOF_CONF_LEVEL * NB_LEVELS)
sta Param_FilesReadWrite+4
lda #>(1 + SIZEOF_CONF_LEVEL * NB_LEVELS)
sta Param_FilesReadWrite+5
; load
jsr ReadFile
; exploit
lda LevelConfigs
sta NbLevels
sta NR_LEVELS
inc NR_LEVELS
level_conf_default:
; level_nr
tya
iny
sta Levels, X
; is_built
lda FALSE
sta Levels+1, x
; seed
lda #0
sta Levels+2, X
sta Levels+3, X
sta Levels+4, X
sta Levels+5, X
; size
; pos_player_enter
lda #$FF
sta Levels+7, X
sta Levels+8, X
; actors
txa
clc
adc #9
tax
lda #eACTORSREACTIVE::AA_NB
sta NR_ACTORS
lda #0
level_conf_actors:
sta Levels, X
inx
dec NR_ACTORS
bne level_conf_actors
dec NR_LEVELS
bne level_conf_default
; level #0
ldx #0
lda #1
sta Levels + 9 + eACTORSREACTIVE::AA_STAIRUP, X
lda #LEVELSIZE::TINY
sta Levels+6, X ; size
; level #1
clc
txa
adc #SIZEOF_CONF_LEVEL
tax
lda #1
sta Levels + 9 + eACTORSREACTIVE::AA_STAIRUP, X
sta Levels + 9 + eACTORSREACTIVE::AA_STAIRDOWN, X
lda #LEVELSIZE::SMALL
sta Levels+6, X ; size
; level #2
clc
txa
adc #SIZEOF_CONF_LEVEL
tax
lda #1
sta Levels + 9 + eACTORSREACTIVE::AA_STAIRUP, X
sta Levels + 9 + eACTORSREACTIVE::AA_STAIRDOWN, X
lda #LEVELSIZE::NORMAL
sta Levels+6, X ; size
; level #3
clc
txa
adc #SIZEOF_CONF_LEVEL
tax
lda #1
sta Levels + 9 + eACTORSREACTIVE::AA_STAIRUP, X
sta Levels + 9 + eACTORSREACTIVE::AA_STAIRDOWN, X
lda #LEVELSIZE::BIG
sta Levels+6, X ; size
; level #4
clc
txa
adc #SIZEOF_CONF_LEVEL
tax
lda #1
sta Levels + 9 + eACTORSREACTIVE::AA_STAIRDOWN, X
lda #LEVELSIZE::HUGE
sta Levels+6, X ; size
; global vars
; global vars
lda #0
sta CurrentLevel
lda FALSE
sta NextLevel
lda #FALSE
sta ExitLevel
rts
@ -151,85 +137,51 @@ level_conf_default:
; @param: Uses NextLevel as level number
.define LEVEL_CONF_OFFSET ZERO_3
.define LEVEL_STATE_OFFSET ZERO_9_1
.define ADDR_LEVEL_CONF ZERO_9_2 ; 2 bytes
level_enter:
; debug:
; lda NextLevel
; cmp #0
; bne debug_end
; jsr Random8
; debug_end:
lda NextLevel
jsr LoadState
jsr Random8_SaveRandomness
lda LevelIsBuilt
cmp #TRUE
beq level_was_built
; get the level conf
lda #0
ldx #0
clc
get_level_conf:
tay
lda Levels, X
cmp NextLevel
beq end_idx_level
tya
adc #SIZEOF_CONF_LEVEL
level_generation:
; compute offset to level config
lda NextLevel
jsr level_get_config_offset
pha
clc
txa
adc #<LevelConfigs
sta ADDR_LEVEL_CONF
pla
adc #>LevelConfigs
sta ADDR_LEVEL_CONF+1
; init maze size
ldy #1
lda (ADDR_LEVEL_CONF), Y ; size
tax
bcc get_level_conf
end_idx_level:
stx LEVEL_CONF_OFFSET
tay
jsr Init_Dimensions_Maze
; init seed for the level if not already built
lda Levels+1, X ; is_built
cmp FALSE
bne end_init_seed
; player position returned in X and Y
jsr Build_Level
jsr player_init ; param: player pos in X and Y
jsr Random8
ldx LEVEL_CONF_OFFSET
sta Levels+2, X ; seed[0]
jsr Random8
ldx LEVEL_CONF_OFFSET
sta Levels+3, X ; seed[1]
jsr Random8
ldx LEVEL_CONF_OFFSET
sta Levels+4, X ; seed[2]
jsr Random8
ldx LEVEL_CONF_OFFSET
sta Levels+5, X ; seed[3]
end_init_seed:
level_was_built:
; init the randomness with the values for the level
lda Levels+2, X ; seed[0]
sta SEED0
lda Levels+3, X ; seed[1]
sta SEED1
lda Levels+4, X ; seed[2]
sta SEED2
lda Levels+5, X ; seed[3]
sta SEED3
jsr Random8_Init
; init maze size
ldx LEVEL_CONF_OFFSET
txa
pha ; save LEVEL_CONF_OFFSET as its ZP will be overwritten
lda Levels+6, X ; size
tax
tay
jsr Init_Dimensions_Maze
ldx ActorPositions + eACTORTYPES::PLAYER
ldy ActorPositions + eACTORTYPES::PLAYER + 1
jsr player_init
; player position returned in X and Y
jsr Build_Level
jsr player_init ; param: player pos in X and Y
level_enter_end:
jsr Random8_RestoreRandomness
pla ; restore LEVEL_CONF_OFFSET
tax
lda TRUE
sta Levels+1, X; is_built
lda FALSE
lda #FALSE
sta ExitLevel
lda NextLevel
@ -238,28 +190,39 @@ end_init_seed:
rts
.import Player_XY
.define Player_XY ActorPositions + eACTORTYPES::PLAYER
level_exit:
; get the level conf
lda #0
ldx #0
clc
get_level_conf_2:
tay
lda Levels, X
cmp CurrentLevel
beq end_idx_level_2
tya
adc #SIZEOF_CONF_LEVEL
tax
bcc get_level_conf_2
end_idx_level_2:
; save player pos in conf
lda Player_XY
sta Levels+7, X
lda Player_XY + 1
sta Levels+8, X
lda CurrentLevel
jsr SaveState
rts
; @param Level_Nr in A
; @return Config offset for the level in X
level_get_config_offset:
sta FAC1
ldx #SIZEOF_CONF_LEVEL
stx FAC2
jsr mul8
; first byte of conf is the number of levels
pha
clc
txa
adc #1
tax
pla
adc #0
rts
; @brief reset the states of all levels
level_reset_states:
lda #0
sta CurrentLevel
lda #NB_LEVELS
jsr ResetIsBuilt
rts

View File

@ -14,14 +14,42 @@
; along with this program. If not, see <http://www.gnu.org/licenses/>.
.include "level_private.inc"
.import levels_init
.import level_enter ; param: A = level_nr
.import level_exit
.import level_get_config_offset
.import CurrentLevel
.import NextLevel
.import ExitLevel
.import Levels
.import LevelConfigs
.import NbLevels
.enum LEVELSIZE
TINY = 20
SMALL = 24
NORMAL = 32
BIG = 48
HUGE = 64
.endenum
; struct Level
; {
; uint8_t is_built;
; uint8_t seed[4]; //< seed used to build the level
; coords_t pos_player_enter; //< position of player when entering the level (x,y)
; }
;
; nb_levels >>>> ALWAYS OFFSET + 1!!! <<<<
; array [
; struct LevelsConf
; {
; uint8_t level_nr;
; uint8_t size; //< eLEVELSIZE
; uint8_t actors[NB_ACTORS_MAX]; //< number of actors of each kind added in the level after building the maze
; }
; ]

View File

@ -15,28 +15,11 @@
; BEWARE: NB_LEVELS * SIZEOF_STATE_LEVEL shall not be > 256
.define SIZEOF_STATE_LEVEL 7
.define SIZEOF_CONF_LEVEL 130 ;( NB_ACTORS_MAX + 2 )
.define NB_LEVELS 3
; typedef struct
; {
; uint8_t level_nr;
; uint8_t is_built;
; uint8_t seed[4]; //< seed used to build the level
; uint8_t size; //< eLEVELSIZE
; coords_t pos_player_enter; //< position of player when entering the level (x,y)
; uint8_t actors[AA_NB]; //< number of reactive actors of each kind in the level
; }
; level_conf_t;
; BEWARE: NB_LEVELS * SIZEOF_CONF_LEVEL shall not be > 256
.define SIZEOF_CONF_LEVEL 12
.define NB_LEVELS 5
.enum LEVELSIZE
TINY = 20
SMALL = 24
NORMAL = 32
BIG = 48
HUGE = 64
.endenum

View File

@ -16,13 +16,14 @@
.include "world.inc"
.include "../common.inc"
.include "../actors/actors.inc"
.include "../tiles.inc"
.include "../random.inc"
.include "../math.inc"
.include "../memory.inc"
.export World
; initializes the world
@ -43,8 +44,11 @@
; DESTROYS A,X,Y, ZERO_2_1, ZERO_2_2, ZERO_2_3
.export Compute_Maze_Addr
; #TRUE if an object has been picked by the player
.export World_PickedObject
.export Tile_player_standing_actor
.define TILE_NR ZERO_2_1
.define COORD_X ZERO_2_1
.define COORD_Y ZERO_2_2
.define OFFSET ZERO_2_2
@ -53,10 +57,13 @@
.BSS
; The tile where the player stands
.struct Tile_player_standing
addr .word ; adress of the location
actor .byte ; actor on the location tile
.endstruct
; The two memory locations must be adjacent
Tile_player_standing_addr: .res 2
Tile_player_standing_actor: .res 1
.DATA
World_PickedObject: .byte 0
.CODE
@ -66,51 +73,65 @@ world_init:
; Saving the first tile on which the player stands
; FIXME player could be standing anywhere on any type of floor
jsr Compute_Maze_Addr
stx Tile_player_standing::addr
sta Tile_player_standing::addr+1
stx ZERO_2_1
sta ZERO_2_1+1
ldy #0
lda (ZERO_2_1), Y
sta Tile_player_standing::actor
stx Tile_player_standing_addr
sta Tile_player_standing_addr+1
lda Tile_player_standing_actor
cmp #UNDEF
bne world_init_end
lda #eACTORTYPES::FLOOR_2
sta Tile_player_standing_actor
world_init_end:
rts
; sets the player's position onto the World
.define PLAYER_XY ZERO_2_1; 2 bytes
.define NEXT_TILE_XY ZERO_2_4 ; 2 bytes
world_set_player:
stx ZERO_2_4
sty ZERO_2_5
stx NEXT_TILE_XY
sty NEXT_TILE_XY+1
; restore the previous tile
ldx Tile_player_standing::addr
lda Tile_player_standing::addr+1
stx ZERO_2_1
sta ZERO_2_1+1
; restore the previous tile
ldx Tile_player_standing_addr
lda Tile_player_standing_addr+1
stx PLAYER_XY
sta PLAYER_XY+1
ldy #0
lda Tile_player_standing::actor
sta (ZERO_2_1), Y
lda Tile_player_standing_actor
sta (PLAYER_XY), Y
; save the next tile
ldx ZERO_2_4
ldy ZERO_2_5
ldx NEXT_TILE_XY
ldy NEXT_TILE_XY+1
jsr Compute_Maze_Addr ; get's player's position address in memory
stx Tile_player_standing::addr
sta Tile_player_standing::addr+1
stx ZERO_2_1
sta ZERO_2_1+1
stx Tile_player_standing_addr
sta Tile_player_standing_addr+1
stx PLAYER_XY
sta PLAYER_XY+1
ldy #0
lda (ZERO_2_1), y
sta Tile_player_standing::actor
lda (PLAYER_XY), y
sta Tile_player_standing_actor
; if an object was picked
; override to force save a floor tile
lda World_PickedObject
cmp #TRUE
bne no_object_picked
lda #eACTORTYPES::FLOOR_2
sta Tile_player_standing_actor
lda #FALSE
sta World_PickedObject
no_object_picked:
; sets the player on the tile
lda #ACTORS::PLAYER
sta (ZERO_2_1), y
lda #eACTORTYPES::PLAYER
sta (PLAYER_XY), y
; restore the given locations
ldx ZERO_2_4
ldy ZERO_2_5
ldx NEXT_TILE_XY
ldy NEXT_TILE_XY+1
rts
@ -147,7 +168,7 @@ Compute_Maze_Addr:
.DATA
.BSS
.align 256

View File

@ -27,31 +27,5 @@
.define WIDTH_WORLD 64
.define NEG_WIDTH_WORLD $C0
.define HEIGHT_WORLD 64
.define NEG_HEIGHT_WORLD 64 $C0
.define NEG_HEIGHT_WORLD $C0
.enum ACTORS
PLAYER = 0
FLOOR_1 = 1
FLOOR_2 ; FLOOR BY DEFAULT
FLOOR_3
FLOOR_4
FLOOR_5
FLOOR_6
STAIR_DOWN
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