Compare commits

...

9 Commits

Author SHA1 Message Date
Christophe Meneboeuf
261b7276b5 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
2022-11-21 11:56:56 +01:00
Christophe Meneboeuf
7c90129e9b auto loader 2021-04-16 23:52:49 +02:00
Christophe Meneboeuf
5bbb62f36a
Update README.md 2021-04-14 23:33:52 +02:00
Christophe Meneboeuf
d1a3affa1d 5 levels to explore 2021-04-14 23:26:21 +02:00
Christophe Meneboeuf
abbd59fd9e Bugfix: bresenham when uniting rooms 2020-10-23 22:21:19 +02:00
Christophe Meneboeuf
4da93af1cb Uniting isolated parts of the maze 2020-10-14 22:53:44 +02:00
Christophe Meneboeuf
3841faa027
Update README.md 2020-01-16 00:02:57 +01:00
Christophe Meneboeuf
eff3827d20 Random level generation (post #3: https://www.xtof.info/blog/?p=1186) 2020-01-15 23:59:25 +01:00
Christophe Meneboeuf
7fcdb9d800
Update README.md 2019-01-09 15:26:04 +01:00
57 changed files with 6275 additions and 1326 deletions

1
.gitignore vendored
View File

@ -1,4 +1,5 @@
.vscode/
.DS_Store
*.out
*.a2
*.o

1348
LICENSE

File diff suppressed because it is too large Load Diff

View File

@ -1,18 +1,23 @@
APPLE2_CL := $(CC65_HOME)/bin/cl65
APPLE2_SRC := src/main.asm src/math.asm src/random.asm \
src/game_loop.asm src/display.asm src/tiles.asm src/world.asm src/player.asm \
src/debug.asm
APPLE2_SRC := src/main.asm src/math.asm src/memory.asm src/random.asm \
src/game_loop.asm src/display.asm src/tiles.asm src/player.asm \
src/world/world.asm src/world/level.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/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/*.s 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,34 +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/blog/?p=1044)
- [Raycasting a Line of Sight](https://www.xtof.info/blog/?p=1071)
- [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*
## Prerequisite in order to produce the disk image
### How to play
- 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,14 +6,26 @@ 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
echo " . revoving previous instance of ESCAPE form the disk"
# ###
# NOTE:
# The loader must have the same basename as the game loaded
# ###
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 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."

View File

@ -38,21 +38,52 @@ def fill_rect(x,y,color):
outline = (0,0,128),
fill = color)
# returns rays from (x0, y0) to (x1, y1)
# output in rays
def compute_rays(x0, y0, x1, y1, rays):
ray = list(bresenham(x0, y0, x1, y1))
# Duplicate the ray so that x and y are not incremented at the same time
duplicated = False
ray_x = [] # x incremented before y
ray_y = [] # y incremented before x
x = ray[0][0]
y = ray[0][1]
for tile in ray[1:]:
if tile[0] != x and tile[1] != y:
duplicated = True
ray_x.append((tile[0], y))
ray_x.append((tile[0], tile[1]))
ray_y.append((x, tile[1]))
ray_y.append((tile[0], tile[1]))
else:
ray_x.append((tile[0], tile[1]))
ray_y.append((tile[0], tile[1]))
x = tile[0]
y = tile[1]
rays.append(ray_x)
if duplicated:
rays.append(ray_y)
return rays
if __name__=="__main__":
rays = []
y = 0
for x in range(0,SIZE_GRID-1):
rays.append(list(bresenham(x_player,y_player,x,y)))
rays = compute_rays(x_player,y_player,x,y, rays)
x = SIZE_GRID-1
for y in range(0,SIZE_GRID-1):
rays.append(list(bresenham(x_player,y_player,x,y)))
rays = compute_rays(x_player,y_player,x,y, rays)
y = SIZE_GRID-1
for x in range(SIZE_GRID-1,0,-1):
rays.append(list(bresenham(x_player,y_player,x,y)))
rays = compute_rays(x_player,y_player,x,y, rays)
x = 0
for y in range(SIZE_GRID-1,0,-1):
rays.append(list(bresenham(x_player,y_player,x,y)))
rays = compute_rays(x_player,y_player,x,y, rays)
# create the grid
@ -67,7 +98,7 @@ if __name__=="__main__":
nb_cells = 0
rgb = 0
for ray in rays:
for tile in ray[1:]:
for tile in ray:
fill_rect(tile[0], tile[1], (rgb,rgb,rgb))
nb_cells += 1
rgb += int(200 / len(rays))
@ -78,8 +109,8 @@ if __name__=="__main__":
str_ray = "; Nb rays: {}\n".format(len(rays))
str_ray += "; A ray: length (nb_tiles), offset_from_view_in_world_low, offset_from_view_in_world_high, offset_view\nRays:\n"
for ray in rays:
str_ray += ".byte " + str(len(ray)-1)
for tile in ray[1:]:
str_ray += ".byte " + str(len(ray))
for tile in ray:
offset_view = tile[0] + SIZE_GRID*tile[1]
offset_world = (tile[0] + WIDTH_WORLD*tile[1])
offset_world_low = offset_world & 0xFF
@ -90,4 +121,4 @@ if __name__=="__main__":
print(str_ray)
Im.show()

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

198
src/actors/reactions.asm Normal file
View File

@ -0,0 +1,198 @@
; Copyright (C) 2020 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 "actors.inc"
.include "../world/level.inc"
.include "../io/textio.inc"
.include "../common.inc"
.export Reactions_lsb
.export Reactions_msb
.export ReactionStairUp
.export ReactionStairDown
.export ReactionMap
.import ActorPositions
.import World_PickedObject
.DATA
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:
; 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
.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, 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, 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, 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, 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, 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, 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, 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, 0
.byte 0, 0, 0, 0, 0, 0, 0, 0
.byte 0, 0, 0, 0, 0, 0, 0
Reactions_msb:
; 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
.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, 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, 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, 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, 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, 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, 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, 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, 0
.byte 0, 0, 0, 0, 0, 0, 0, 0
.byte 0, 0, 0, 0, 0, 0, 0
.CODE
ReactionFloor:
lda #TRUE
rts
ReactionWall:
PRINT STR_REACTION_WALL
lda #FALSE
rts
ReactionStairUp:
PRINT STR_REACTION_STAIR_UP
lda CurrentLevel
sta NextLevel
inc NextLevel
lda #TRUE
sta ExitLevel
lda #FALSE
rts
ReactionStairDown:
PRINT STR_REACTION_STAIR_DOWN
lda CurrentLevel
sta NextLevel
dec NextLevel
lda #TRUE
sta ExitLevel
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

32
src/builder/actors.inc Normal file
View File

@ -0,0 +1,32 @@
.define NB_ACTORS_MAX 128
.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

339
src/builder/builder.asm Normal file
View File

@ -0,0 +1,339 @@
; Copyright (C) 2019 Christophe Meneboeuf <christophe@xtof.info>
;
; This program is free software: you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
; the Free Software Foundation, either version 3 of the License, or
; (at your option) any later version.
;
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
; GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public License
; along with this program. If not, see <http://www.gnu.org/licenses/>.
; All the dungeon builder is based on this article: http://journal.stuffwithstuff.com/2014/12/21/rooms-and-mazes/
.include "rooms.inc"
.include "maze.inc"
.include "unite.inc"
.include "../common.inc"
.include "../actors/actors.inc"
.include "../io/textio.inc"
.include "../math.inc"
.include "../monitor.inc"
.include "../memory.inc"
.include "../world/world.inc"
.include "../world/level.inc"
; code
.import Random8
.import Grow_Maze ; to patch
.import Compute_Maze_Addr
.import Place_Actors
; data
.import World
.import Tile_player_standing_actor
.export Init_Dimensions_Maze
.export Build_Level
.export Rooms
.export WIDTH_MAZE
.export HEIGHT_MAZE
.BSS
; Describes a room to be built
; typedef struct {
; uint8_t height;
; uint8_t width;
; uint8_t x;
; uint8_t y;
; } room_t;
.define SIZEOF_ROOM_T 4
.align 256
Rooms: .res SIZEOF_ROOM_T*MAX_NB_ROOMS ; MAX 1 page of data!
WIDTH_MAZE: .res 1
HEIGHT_MAZE: .res 1
.DATA
STR_SIZE_MAZE_1: ASCIIZ "PLEASE ENTER THE SIZE OF THE LEVEL."
STR_SIZE_MAZE_2: ASCIIZ "A:TINY B:SMALL C:NORMAL D:BIG E:HUGE"
STR_SIZE_MAZE_3: ASCIIZ "PLEASE ENTER A VALID CHOICE."
STR_ROOMS: ASCIIZ "CARVING ROOMS..."
STR_MAZE: ASCIIZ "GROWING THE MAZE..."
STR_DOORS: ASCIIZ "OPENING DOORS..."
STR_DEADENDS: ASCIIZ "FILLING DEAD ENDS..."
STR_UNITE: ASCIIZ "UNITING THE ROOMS..."
STR_ACTORS: ASCIIZ "PLACING ACTORS..."
.CODE
; @brief Fills border walls
; @param type of the "wall" in A
; destroys ZERO_2_1, ZERO_2_2
.define ADDR_WORLD ZERO_2_1
.macro WORLD_NEXT_LINE
clc
lda ADDR_WORLD
adc #WIDTH_WORLD
sta ADDR_WORLD
lda ADDR_WORLD+1
adc #0
sta ADDR_WORLD+1
.endmacro
; DO NOT MESS WITH THIS FUNCTION: IT IS PATCHED!!
.define PATCH_WIDTH_MAZE_1 0
.define PATCH_HEIGHT_MAZE_2 0
_build_fences:
ldx #<World
stx ADDR_WORLD
ldx #>World
stx ADDR_WORLD+1
ldy #PATCH_WIDTH_MAZE_1
loop_wall_top:
sta (ADDR_WORLD), Y
dey
bne loop_wall_top
sta (ADDR_WORLD), Y
ldx #PATCH_HEIGHT_MAZE_2
loop_wall_left_right:
pha
WORLD_NEXT_LINE
pla
ldy #PATCH_WIDTH_MAZE_1
sta (ADDR_WORLD), Y
ldy #0
sta (ADDR_WORLD), Y
dex
bne loop_wall_left_right
pha
WORLD_NEXT_LINE
pla
ldy #PATCH_WIDTH_MAZE_1
loop_wall_bottom:
sta (ADDR_WORLD), Y
dey
bne loop_wall_bottom
sta (ADDR_WORLD), Y
rts
.undefine ADDR_WORLD
; @brief Sets the Maze's dimentions
; @param width in X
; @param height in Y
Init_Dimensions_Maze:
stx WIDTH_MAZE
; patch WIDTH_MAZE usage NO MORE PATCH: comment to be removed
dex
stx _build_fences + $9
stx _build_fences + $23
stx _build_fences + $3D
; patch HEIGHT_MAZE usage NO MORE PATCH: comment to be removed
sty HEIGHT_MAZE
dey
dey
sty _build_fences + $12
rts
; @brief Builds a whole level
; @param Uses NextLevel to get the conf
; @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 ; use same location as Place_Actors
Build_Level:
lda #UNDEF
sta Tile_player_standing_actor
; Filling World with eACTORTYPES::WALL_1
ldy #HEIGHT_WORLD
init_world:
ldx #0
init_world_line:
lda #eACTORTYPES::WALL_1
sta DST_WORLD, x
inx
cpx #WIDTH_WORLD
bne init_world_line
; patching DST_WORLD
lda ADDR_TO_PATCH
clc
adc #WIDTH_WORLD
sta ADDR_TO_PATCH
lda ADDR_TO_PATCH + 1
adc #0
sta ADDR_TO_PATCH + 1
dey
bne init_world
; patching back for a future execution
lda #<DST_WORLD
sta ADDR_TO_PATCH
lda #>DST_WORLD
sta ADDR_TO_PATCH+1
PRINT STR_ROOMS
lda #MAX_NB_ROOMS+1
jsr Carve_Rooms
sta NB_ROOMS
lda #eACTORTYPES::FLOOR_1
jsr _build_fences
PRINT STR_MAZE
jsr Grow_Maze
lda #eACTORTYPES::WALL_1
jsr _build_fences
PRINT STR_DOORS
.define PERCENT_7 #17
ldx PERCENT_7
lda NB_ROOMS
jsr Connect_Rooms
PRINT STR_DEADENDS
jsr Remove_Dead_Ends
PRINT STR_UNITE
jsr Unite_Rooms
; 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_NB ZERO_4_2
.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
; place actors
PRINT STR_ACTORS
; offset to level conf
lda NextLevel
jsr level_get_config_offset
pha
clc
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_id:
beq end_loop_actor_id
jsr Place_Actors
; save stair down position
lda ACTOR_TYPE
cmp #eACTORTYPES::STAIR_DOWN
bne not_stair_down
lda POS_X
sta POS_STARDOWN_X
lda POS_Y
sta POS_STARDOWN_Y
not_stair_down:
inc ACTOR_ID
dec ACTOR_NB ; next
lda ACTOR_NB
jmp loop_actor_id
end_loop_actor_id:
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
; 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
jsr Compute_Maze_Addr
; addr offseted by - witdh_maze to access all tiles with offset
sta ADDR_ACTOR+1
txa
sec
sbc #WIDTH_WORLD
sta ADDR_ACTOR
lda ADDR_ACTOR+1
sbc #0
sta ADDR_ACTOR+1
ldx POS_STARDOWN_X
; NOTE: There is at least one solution, the tile is not surrounded!
; if (World[pos_stair_down.y][pos_stair_down.x - 1] == FLOOR_2)
ldy #(WIDTH_WORLD - 1)
lda (ADDR_ACTOR), Y
cmp #eACTORTYPES::FLOOR_2
bne not_x_minus
ldy POS_STARDOWN_Y
dex
rts
not_x_minus:
; if (World[pos_stair_down.y - 1][pos_stair_down.x] == FLOOR_2)
ldy #0
lda (ADDR_ACTOR), Y
cmp #eACTORTYPES::FLOOR_2
bne not_y_minus
ldy POS_STARDOWN_Y
dey
rts
not_y_minus:
; if (World[pos_stair_down.y + 1][pos_stair_down.x] == FLOOR_2)
ldy #(WIDTH_WORLD * 2)
lda (ADDR_ACTOR), Y
cmp #eACTORTYPES::FLOOR_2
bne not_y_plus
ldy POS_STARDOWN_Y
iny
rts
not_y_plus:
ldy POS_STARDOWN_Y
inx
rts

18
src/builder/builder.inc Normal file
View File

@ -0,0 +1,18 @@
; Copyright (C) 2019 Christophe Meneboeuf <christophe@xtof.info>
;
; This program is free software: you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
; the Free Software Foundation, either version 3 of the License, or
; (at your option) any later version.
;
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
; GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public License
; along with this program. If not, see <http://www.gnu.org/licenses/>.
.import Init_Dimensions_Maze
.import Build_Level
.import Rooms

534
src/builder/maze.asm Normal file
View File

@ -0,0 +1,534 @@
; Copyright (C) 2019 Christophe Meneboeuf <christophe@xtof.info>
;
; This program is free software: you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
; the Free Software Foundation, either version 3 of the License, or
; (at your option) any later version.
;
; This program is distributed in the hope that it will be usefuELEFT,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
; GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public License
; along with this program. If not, see <http://www.gnu.org/licenses/>.
.include "../memory.inc"
.include "../random.inc"
.include "../math.inc"
.include "../common.inc"
.include "../world/world.inc"
.include "../actors/actors.inc"
.export Grow_Maze
.export Remove_Dead_Ends
.import Compute_Maze_Addr
.import World
.import WIDTH_MAZE
.import HEIGHT_MAZE
; using HGR2 space as the stack
; Stack contains pointers to tiles (2 byte long)
.define STACK_ADDR $3FFE ; Will be 2 byte incremented before 1st push
.define Y_TILE ZERO_2_4
.define X_TILE ZERO_2_5
.define PTR_STACK ZERO_4_1 ; 2 bytes
.define PTR_NEW_TILE ZERO_4_3 ; 2 bytes
; increments the stack pointer then pushes address A:X (little endian)
; *ptr_stack = x
; *(ptr_stack+1) = a
; ptr_stack += 2
.macro PUSHAX
pha
; increment stack pointer
clc
lda PTR_STACK
adc #2
sta PTR_STACK
lda PTR_STACK+1
adc #0
sta PTR_STACK+1
; push A:X to the stack
pla
ldy #1
sta (PTR_STACK),Y
dey
txa
sta (PTR_STACK),Y
.endmacro
; ptr_newtile is offseted by -WIDTH_WORLD so we can access all its neighbors
; with positive offsets using Y indirect addressing
.macro PTR_UP_TILE
sec
ldy #0
lda (PTR_STACK),Y
sbc #(2*WIDTH_WORLD)
sta PTR_NEW_TILE
iny
lda (PTR_STACK),Y
sbc #0
sta PTR_NEW_TILE+1
.endmacro
.macro PTR_LEFT_TILE
sec
ldy #0
lda (PTR_STACK),Y
sbc #(WIDTH_WORLD+1)
sta PTR_NEW_TILE
iny
lda (PTR_STACK),Y
sbc #0
sta PTR_NEW_TILE+1
.endmacro
.macro PTR_RIGHT_TILE
sec
ldy #0
lda (PTR_STACK),Y
sbc #(WIDTH_WORLD-1)
sta PTR_NEW_TILE
iny
lda (PTR_STACK),Y
sbc #0
sta PTR_NEW_TILE+1
.endmacro
.macro PTR_DOWN_TILE
ldy #0
lda (PTR_STACK),Y
sta PTR_NEW_TILE
iny
lda (PTR_STACK),Y
sta PTR_NEW_TILE+1
.endmacro
.macro PTR_CURR_TILE
sec
ldy #0
lda (PTR_STACK),Y
sbc #(WIDTH_WORLD)
sta PTR_NEW_TILE
iny
lda (PTR_STACK),Y
sbc #0
sta PTR_NEW_TILE+1
.endmacro
; test if the tile offseted from PTR_NEW_TILE is walkable
.macro ISWALKABLE offset
ldy offset
lda (PTR_NEW_TILE),Y
cmp #eACTORTYPES::LAST_FLOOR+1
bcc cannot_carve
.endmacro
.define OFFSET_NIL #WIDTH_WORLD
.define OFFSET_UP #0
.define OFFSET_RIGHT #(WIDTH_WORLD+1)
.define OFFSET_DOWN #(2*WIDTH_WORLD)
.define OFFSET_LEFT #(WIDTH_WORLD-1)
.macro IS_TILE_WALLED
PTR_CURR_TILE
ldy OFFSET_NIL
lda (PTR_NEW_TILE),Y
cmp #eACTORTYPES::LAST_FLOOR
bcc end_loop_stack
ldy OFFSET_UP
lda (PTR_NEW_TILE),Y
cmp #eACTORTYPES::LAST_FLOOR
bcc end_loop_stack
ldy OFFSET_RIGHT
lda (PTR_NEW_TILE),Y
cmp #eACTORTYPES::LAST_FLOOR
bcc end_loop_stack
ldy OFFSET_DOWN
lda (PTR_NEW_TILE),Y
cmp #eACTORTYPES::LAST_FLOOR
bcc end_loop_stack
ldy OFFSET_LEFT
lda (PTR_NEW_TILE),Y
cmp #eACTORTYPES::LAST_FLOOR
bcc end_loop_stack
.endmacro
; @brief Fills the empty space with a perfect maze
.define PATCH_WIDTH_MAZE_4 0
.define PATCH_HEIGHT_MAZE_4 0
Grow_Maze:
; Groth start location
ldx #2
stx X_TILE
stx Y_TILE
loop_grow_maze:
; init the stack
lda #<STACK_ADDR
sta PTR_STACK
lda #>STACK_ADDR
sta PTR_STACK+1
; Test if the tile is suitable
ldy Y_TILE
ldx X_TILE
jsr Compute_Maze_Addr ; result addr in A:X
; test if the tile is walled
PUSHAX
IS_TILE_WALLED
; carve
ldy #WIDTH_WORLD
lda #eACTORTYPES::FLOOR_1
sta (PTR_NEW_TILE),Y
.define IDX ZERO_2_6
; while the stack is not empty: carve
loop_stack:
jsr _random_directions
tax
stx IDX
loop_find_dir: ; find a direction suitable to carvingm
jsr _can_carve
cmp #1 ; cannot carve -> test other directions
beq carve_the_tile
lda IDX
and #3 ; 4th direction?
cmp #3
beq test_stack
inc IDX
ldx IDX
jmp loop_find_dir
test_stack:
lda PTR_STACK+1
cmp #>(STACK_ADDR+2)
bne unstack
lda PTR_STACK
cmp #<(STACK_ADDR+2)
beq end_loop_stack ; stack is empty -> break
unstack:
sec
lda PTR_STACK
sbc #2
sta PTR_STACK
lda PTR_STACK+1
sbc #0
sta PTR_STACK+1
jmp loop_stack
carve_the_tile:
; carve the tile
ldy #0
lda #eACTORTYPES::FLOOR_1
sta (PTR_NEW_TILE),Y
jmp loop_stack
end_loop_stack:
inc X_TILE
ldx WIDTH_MAZE
dex
dex
cpx X_TILE
beq incr_y_tile
jmp loop_grow_maze
incr_y_tile:
ldx #2
stx X_TILE
inc Y_TILE
ldy HEIGHT_MAZE
dey
cpy Y_TILE
beq end_loop_grow_maze
jmp loop_grow_maze
end_loop_grow_maze:
rts
.enum
EUP = 0
ERIGHT
EDOWN
ELEFT
.endenum
; 24 direction quartets
RandomDirection:
.byte EUP,ERIGHT,EDOWN,ELEFT,EUP,ERIGHT,ELEFT,EDOWN,EUP,EDOWN,ERIGHT,ELEFT,EUP,EDOWN,ELEFT,ERIGHT,EUP,ELEFT,ERIGHT,EDOWN,EUP,ELEFT,EDOWN,ERIGHT
.byte ERIGHT,EUP,EDOWN,ELEFT,ERIGHT,EUP,ELEFT,EDOWN,ERIGHT,EDOWN,EUP,ELEFT,ERIGHT,EDOWN,ELEFT,EUP,ERIGHT,ELEFT,EUP,EDOWN,ERIGHT,ELEFT,EDOWN,EUP
.byte EDOWN,ERIGHT,EUP,ELEFT,EDOWN,ERIGHT,ELEFT,EUP,EDOWN,ELEFT,EUP,ERIGHT,EDOWN,ELEFT,ERIGHT,EUP,EDOWN,EUP,ELEFT,ERIGHT,EDOWN,EUP,ERIGHT,ELEFT
.byte ELEFT,ERIGHT,EDOWN,EUP,ELEFT,ERIGHT,EDOWN,EUP,ELEFT,EDOWN,ERIGHT,EUP,ELEFT,EDOWN,EUP,ERIGHT,ELEFT,EUP,ERIGHT,EDOWN,ELEFT,EUP,EDOWN,ERIGHT
; Uses a precomputed table to quickly return an offset to one of the direction quartets
_random_directions:
jsr Random8
and #31
ldx #24
jsr Modulus
asl
asl ; offset to a direction quartet
rts
; @brief Returns A=1 if the tile can be carved, A=0 otherwise.
; some difficulties for the branches to be in range to end_can_carve.
; thus the jsr and jmp and the breakdown of the routine
_can_carve:
lda RandomDirection,X
can_carve_up:
cmp #EUP
bne can_carve_right
jmp _can_carve_up
can_carve_right:
cmp #ERIGHT
bne can_carve_down
jmp _can_carve_right
can_carve_down:
cmp #EDOWN
bne can_carve_left
PTR_DOWN_TILE ; ptr_newtile = down - width_world
ISWALKABLE OFFSET_NIL ; the new tile
ISWALKABLE OFFSET_RIGHT ; new tile's right neighbor
ISWALKABLE OFFSET_DOWN ; new tile's bottom neighbor
ISWALKABLE OFFSET_LEFT ; new tile's left neighbor
jmp _save_ptr_newtile
can_carve_left:
cmp #ELEFT
bne end_can_carve
PTR_LEFT_TILE ; ptr_newtile = left - width_world
ISWALKABLE OFFSET_NIL ; the new tile
ISWALKABLE OFFSET_UP ; new tile's upper neighbor
ISWALKABLE OFFSET_DOWN ; new tile's bottom neighbor
ISWALKABLE OFFSET_LEFT ; new tile's left neighbor
jmp _save_ptr_newtile
cannot_carve:
lda #0
end_can_carve:
rts
_can_carve_up:
PTR_UP_TILE ; ptr_newtile = up - width_world
ISWALKABLE OFFSET_NIL ; the new tile
ISWALKABLE OFFSET_UP ; new tile's upper neighbor
ISWALKABLE OFFSET_RIGHT ; new tile's right neighbor
ISWALKABLE OFFSET_LEFT ; new tile's left neighbor
jmp _save_ptr_newtile
_can_carve_right:
PTR_RIGHT_TILE ; ptr_newtile = rigth - width_world
ISWALKABLE OFFSET_NIL ; the new tile
ISWALKABLE OFFSET_RIGHT ; new tile's right neighbor
ISWALKABLE OFFSET_DOWN ; new tile's bottom neighbor
ISWALKABLE OFFSET_UP ; new tile's upper neighbor
; jmp _save_ptr_newtile
; save new tile on the stack
_save_ptr_newtile:
clc
lda PTR_NEW_TILE
adc #WIDTH_WORLD
sta PTR_NEW_TILE
tax
lda PTR_NEW_TILE+1
adc #0
sta PTR_NEW_TILE+1
PUSHAX
;CREUSER???
lda #1
jmp end_can_carve
.undefine Y_TILE
.undefine X_TILE
.undefine PTR_STACK
.undefine PTR_NEW_TILE
.define PTR_TILE ZERO_2_1 ; 2 bytes
.define PTR_NEXT_TILE ZERO_2_3 ; 2 bytes
.define NB_WALLS ZERO_2_5
.define ADDR_END ZERO_4_1 ; 2 bytes
.define HEIGHTxWIDTH WIDTH_WORLD*HEIGHT_WORLD
; @brief Removes all the dead ends
Remove_Dead_Ends:
; Compute addr_end as the preprocessor cannot handle 16bit multiplications (???)
lda #WIDTH_WORLD
sta FAC1
lda #HEIGHT_WORLD
sta FAC2
jsr mul8
sta ADDR_END+1
stx ADDR_END
lda #<World
clc
adc ADDR_END
sta ADDR_END
lda #>World
adc ADDR_END+1
sta ADDR_END+1
; starting tile: offsetted by - width_world
lda #<(World + 1) ; &World[1][1] - width_world
sta PTR_TILE
lda #>(World + 1)
sta PTR_TILE+1
loop_tiles:
jsr _is_tile_dead_end
lda NB_WALLS
cmp #3
bcc next_tile
jsr _follow_dead_end
next_tile:
clc
lda PTR_TILE
adc #1
sta PTR_TILE
lda PTR_TILE+1
adc #0
sta PTR_TILE+1
; end?
lda PTR_TILE+1
cmp ADDR_END+1
bne loop_tiles
lda PTR_TILE
cmp ADDR_END
bne loop_tiles
end_loop_tiles:
rts
.undefine ADDR_END
_follow_dead_end:
; saving ptr_tile
lda PTR_TILE
pha
lda PTR_TILE+1
pha
loop_follow:
ldy #WIDTH_WORLD
lda #eACTORTYPES::WALL_1
sta (PTR_TILE), Y
lda PTR_NEXT_TILE
sta PTR_TILE
lda PTR_NEXT_TILE+1
sta PTR_TILE+1
jsr _is_tile_dead_end
lda NB_WALLS
cmp #3
bcs loop_follow
end_loop_follow:
; restoring ptr_tile
pla
sta PTR_TILE+1
pla
sta PTR_TILE
rts
.define ADD_FACTOR ZERO_4_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
_is_tile_dead_end:
lda #0
sta NB_WALLS
ldy #WIDTH_WORLD
sty ADD_FACTOR
; Returns if the tile is a wall
lda #eACTORTYPES::LAST_FLOOR
cmp (PTR_TILE), Y
bcc end_tst_up_tile
tst_up_tile:
ldy #0
cmp (PTR_TILE), Y
bcc up_non_walkable
sty ADD_FACTOR
bcs tst_right_tile
up_non_walkable:
inc NB_WALLS
tst_right_tile:
ldy #(WIDTH_WORLD + 1)
cmp (PTR_TILE), Y
bcc right_non_walkable
sty ADD_FACTOR
bcs tst_down_tile
right_non_walkable:
inc NB_WALLS
tst_down_tile:
ldy #(2*WIDTH_WORLD)
cmp (PTR_TILE), Y
bcc down_non_walkable
sty ADD_FACTOR
bcs tst_left_tile
down_non_walkable:
inc NB_WALLS
tst_left_tile:
ldy #(WIDTH_WORLD - 1)
cmp (PTR_TILE), Y
bcc left_non_walkable
sty ADD_FACTOR
bcs end_tests
left_non_walkable:
inc NB_WALLS
end_tests:
; computing ptr_next_tile
clc
lda PTR_TILE
adc ADD_FACTOR
sta PTR_NEXT_TILE
lda PTR_TILE+1
adc #0
sta PTR_NEXT_TILE+1
; offseting ptr_next_tile
sec
lda PTR_NEXT_TILE
sbc #WIDTH_WORLD
sta PTR_NEXT_TILE
lda PTR_NEXT_TILE+1
sbc #0
sta PTR_NEXT_TILE+1
end_tst_up_tile:
rts

2
src/builder/maze.inc Normal file
View File

@ -0,0 +1,2 @@
.import Grow_Maze
.import Remove_Dead_Ends

662
src/builder/rooms.asm Normal file
View File

@ -0,0 +1,662 @@
; Copyright (C) 2019 Christophe Meneboeuf <christophe@xtof.info>
;
; This program is free software: you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
; the Free Software Foundation, either version 3 of the License, or
; (at your option) any later version.
;
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
; GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public License
; along with this program. If not, see <http://www.gnu.org/licenses/>.
.include "../memory.inc"
.include "../random.inc"
.include "../math.inc"
.include "../common.inc"
.include "../world/world.inc"
.include "../actors/actors.inc"
.export Carve_Rooms
.export Connect_Rooms
.import Rooms
.import Compute_Maze_Addr
.import World
.import WIDTH_MAZE
.import HEIGHT_MAZE
.BSS
; Configration to build rooms
; FIXME??? CA65 will locate this struct at address 0 !!!
.struct Config_Room
width_min .byte
width_max .byte
height_min .byte
height_max .byte
.endstruct
.CODE
.define NB_ATTEMPTS ZERO_2_1
.define NB_ROOMS_OK ZERO_2_2
.define NB_ROOMS_TO_DRAW NB_ATTEMPTS
.define IDX_ROOMS ZERO_3
; @params A nb_attempts
; @returns NB_ROOMS_OK in A
Carve_Rooms:
sta NB_ATTEMPTS
; height_max + width_max shall be < 64
lda #9
sta Config_Room::height_max
lda #3
sta Config_Room::height_min
lda #11
sta Config_Room::width_max
lda #3
sta Config_Room::width_min
ldx #0
stx NB_ROOMS_OK
loop_rooms:
dec NB_ATTEMPTS
beq end_loop_rooms
lda NB_ROOMS_OK ; NB_ROOMS_OK*sizeof(room_t) -> X
asl
asl
tax
jsr _Build_Room
lda NB_ROOMS_OK
jsr _Is_intersecting
cmp #TRUE ; not intersecting with another room?
beq loop_rooms
inc NB_ROOMS_OK
jmp loop_rooms
end_loop_rooms:
lda NB_ROOMS_OK
sta NB_ROOMS_TO_DRAW
ldx #0
loop_draw_rooms:
jsr _Draw_Room
inx
inx
inx
inx
dec NB_ROOMS_TO_DRAW
bne loop_draw_rooms
end_loop_draw_rooms:
lda NB_ROOMS_OK
rts
.undefine NB_ATTEMPTS
.undefine NB_ROOMS_OK
.undefine NB_ROOMS_TO_DRAW
.undefine IDX_ROOMS
.define ADDR_WORLD ZERO_2_3 ; 2 bytes
.define NB_LINE ZERO_2_5
.define LINE_LENGTH ZERO_2_6
.define IDX_ROOMS ZERO_3
_Draw_Room:
stx IDX_ROOMS
ldy Rooms+3, X ; room->y
lda Rooms+2, X ; rooms->x
tax
PUSH ZERO_2_1
PUSH ZERO_2_2
jsr Compute_Maze_Addr
stx ADDR_WORLD
sta ADDR_WORLD+1
POP ZERO_2_2
POP ZERO_2_1
ldx IDX_ROOMS
ldy Rooms, X ; room->height
sty NB_LINE
lda Rooms+1, X ; room->width
sta LINE_LENGTH
loop_draw_line:
lda #eACTORTYPES::FLOOR_1
ldy #0
loop_draw_tile:
sta (ADDR_WORLD), Y
iny
cpy LINE_LENGTH
bne loop_draw_tile
end_loop_draw_tile:
clc
lda ADDR_WORLD
adc #WIDTH_WORLD
sta ADDR_WORLD
lda ADDR_WORLD+1
adc #0
sta ADDR_WORLD+1
dec NB_LINE
bne loop_draw_line
end_loop_draw_line:
ldx IDX_ROOMS
rts
.undefine ADDR_WORLD
.undefine NB_LINE
.undefine LINE_LENGTH
.undefine IDX_ROOMS
.define MODULUS ZERO_2_3
.define WIDTH_ROOM ZERO_2_5
.define HEIGHT_ROOM ZERO_2_6
.define OFFSET_ROOMS ZERO_5_1
; @param X offset to the room to be built from Rooms
; @return offset room in X
_Build_Room:
stx OFFSET_ROOMS
; room.height = config->height_min + Random8() % (config->height_max - config->height_min - 1);
sec
lda Config_Room::height_max
sbc Config_Room::height_min
sbc #1
sta MODULUS
jsr Random8
and #7
ldx MODULUS
jsr Modulus
ldx OFFSET_ROOMS
clc
adc Config_Room::height_min
ora #1
sta Rooms, x ; height
sta HEIGHT_ROOM
inx
stx OFFSET_ROOMS
; room.width = config->width_min + Random8() % (config->width_max - config->width_min - 1);
sec
lda Config_Room::width_max
sbc Config_Room::width_min
sbc #1
sta MODULUS
jsr Random8
and #$F ; room's height shall be < 16
ldx MODULUS
jsr Modulus
ldx OFFSET_ROOMS
clc
adc Config_Room::width_min
ora #1
sta Rooms, x ; width
sta WIDTH_ROOM
inx
stx OFFSET_ROOMS
; room.x = 3 + Random8() % (WIDTH_MAZE - room.width - 5);
sec
lda WIDTH_MAZE
sbc WIDTH_ROOM
sbc #5
sta MODULUS
jsr Random8
and #$7F
ldx MODULUS
jsr Modulus
ldx OFFSET_ROOMS
clc
adc #3
ora #1
sta Rooms, x ; x
inx
stx OFFSET_ROOMS
; room.y = 3 + Random8() % (HEIGHT_MAZE - room.height - 5);
sec
lda HEIGHT_MAZE
sbc HEIGHT_ROOM
sbc #5
sta MODULUS
jsr Random8
and #$7F
ldx MODULUS
jsr Modulus
ldx OFFSET_ROOMS
clc
adc #3
ora #1
sta Rooms, x ; y
inx
stx OFFSET_ROOMS
rts
.undefine MODULUS
.undefine WIDTH_ROOM
.undefine HEIGHT_ROOM
.undefine OFFSET_ROOMS
; @brief test ifthe room is intersecting with other rooms
; @param A : nb rooms already carved
; @return 0 if no intersection, 1 otherwise
.define NB_ROOMS ZERO_3
.define OFFSET_Y ZERO_2_4
.define OFFSET_X ZERO_2_5
_Is_intersecting:
cmp #0
bne compare
; first room
lda #FALSE
clc
bcc end_intersecting ; branch always
; previous rooms were carved
compare:
sta NB_ROOMS
asl ; * sizeof(room_t) to get offset to the last room randomized
asl
tax ; offset to new room in X
stx OFFSET_X
ldy #0 ; offset to carved rooms in Y
loop_intersecting: ; each test must be true
sty OFFSET_Y
clc
lda Rooms+2, Y ; room->x
adc Rooms+1, Y ; room->width
cmp Rooms+2, X
bcc false ; branch if room->x + room->width < new_room->x
clc
lda Rooms+2, X ; new_room->x
adc Rooms+1, X ; new_room->width
cmp Rooms+2, Y ; room->x
bcc false ; branch if new_room->x + new_room->width < room->x
clc
lda Rooms+3, Y ; room->y
adc Rooms, Y ; room->height
cmp Rooms+3, X ; new_room->y
bcc false ; branch if room->y + room->height < new_room->y
clc
lda Rooms+3, X ; new_room->y
adc Rooms, X ; new_room->height
cmp Rooms+3, Y ; room->y
bcc false ; branch if new_room->y + new_room->height < room->y
; all test are true: rooms are intersecting
lda #TRUE ; return value
clc
bcc end_intersecting
false:
ldx OFFSET_X
lda OFFSET_Y
adc #4
tay
dec NB_ROOMS
bne loop_intersecting
lda #FALSE ; no room intersects
end_intersecting:
rts
; using HGR2 space as the stack
; Stack contains pointers to the tiles encompassing a room (except the corners)
.define STACK_ADDR $4000
.define PTR_TILE_TOP ZERO_2_3 ; 2 bytes
.define PTR_TILE_BOT ZERO_4_4 ; 2 bytes
.define PTR_TILE_LEFT ZERO_2_3 ; 2 bytes
.define PTR_TILE_RIGHT ZERO_4_4 ; 2 bytes
.define PTR_TILE ZERO_2_1
.define PTR_STACK ZERO_4_1 ; 2 bytes
.define PROBABILITY_OPENING ZERO_4_3
.define NB_DOORS ZERO_5_1
.define NB_WALKABLE ZERO_5_2
.define SIZE_STACK ZERO_5_3 ; 2 bytes
.define WIDTH_ROOM ZERO_2_5
.define HEIGHT_ROOM ZERO_2_6
.define OFFSET_ROOMS ZERO_5_5
; @brief Connects the rooms to the maze's galleries
; @param A number of rooms
; @param X probability to make an opening in a wall tile
; @detail One opening is made, then all remaning encompassing wall tiles
; can be opened. Depending on the provided probability
Connect_Rooms:
sta NB_ROOMS
stx PROBABILITY_OPENING
lda #0
sta OFFSET_ROOMS
; for each room
loop_connect_rooms:
; # Build a stack of encompassing tiles. Except corners
lda #<STACK_ADDR
sta PTR_STACK
lda #>STACK_ADDR
sta PTR_STACK+1
; ## stacking horizontal walls
; ### init ptr_top
ldx OFFSET_ROOMS
inx
inx
lda Rooms, X ; room->x
sta PTR_TILE_TOP
clc
lda #<World
adc PTR_TILE_TOP
sta PTR_TILE_TOP
lda #>World
adc #0
sta PTR_TILE_TOP+1
inx
lda Rooms, X ; room->y
tax
dex
stx FAC1
lda #WIDTH_WORLD
sta FAC2
jsr mul8
tay
txa
clc
adc PTR_TILE_TOP
sta PTR_TILE_TOP
tya
adc PTR_TILE_TOP+1
sta PTR_TILE_TOP+1
; ### init ptr_bottom
ldx OFFSET_ROOMS
lda Rooms, X ; room->height
sta HEIGHT_ROOM
tax
inx
stx FAC1
lda #WIDTH_WORLD
sta FAC2
jsr mul8
tay
txa
clc
adc PTR_TILE_TOP
sta PTR_TILE_BOT
tya
adc PTR_TILE_TOP+1
sta PTR_TILE_BOT+1
; ## stacking
ldx OFFSET_ROOMS
inx
lda Rooms, X ; room->width
sta WIDTH_ROOM
; for x = 0; x < room->width; x++
ldx #0
loop_stack_horiz:
ldy #0
clc
txa
adc PTR_TILE_TOP
sta (PTR_STACK), Y
iny
lda #0
adc PTR_TILE_TOP+1
sta (PTR_STACK), Y
iny
txa
adc PTR_TILE_BOT
sta (PTR_STACK), Y
iny
lda #0
adc PTR_TILE_BOT+1
sta (PTR_STACK), Y
iny
; incr ptr_stack
tya
clc
adc PTR_STACK
sta PTR_STACK
lda #0
adc PTR_STACK+1
sta PTR_STACK+1
; next x
inx
cpx WIDTH_ROOM
bne loop_stack_horiz
; ## stacking vertical walls
; ### init ptr_left
clc
lda #(WIDTH_WORLD-1)
adc PTR_TILE_TOP
sta PTR_TILE_LEFT
lda #0
adc PTR_TILE_TOP+1
sta PTR_TILE_LEFT+1
; ### init ptr_right
clc
lda WIDTH_ROOM
adc #1
adc PTR_TILE_LEFT
sta PTR_TILE_RIGHT
lda #0
adc PTR_TILE_LEFT+1
sta PTR_TILE_RIGHT+1
; ### stacking
; for y = 0; y < room->height; y++
ldx #0
loop_stack_vertical:
ldy #1
lda PTR_TILE_LEFT+1
sta (PTR_STACK), Y
dey
lda PTR_TILE_LEFT
sta (PTR_STACK), Y
clc
adc #WIDTH_WORLD
sta PTR_TILE_LEFT
lda PTR_TILE_LEFT+1
adc #0
sta PTR_TILE_LEFT+1
iny
iny
iny
lda PTR_TILE_RIGHT+1
sta (PTR_STACK), Y
dey
lda PTR_TILE_RIGHT
sta (PTR_STACK), Y
clc
adc #WIDTH_WORLD
sta PTR_TILE_RIGHT
lda PTR_TILE_RIGHT+1
adc #0
sta PTR_TILE_RIGHT+1
; incr ptr_stack
clc
lda #4
adc PTR_STACK
sta PTR_STACK
lda #0
adc PTR_STACK+1
sta PTR_STACK+1
; next y
inx
cpx HEIGHT_ROOM
bne loop_stack_vertical
; ## Compute stack's size
; UTILISER DIRECTEMENT L ADRESSE DE FIN ET BREAKER QUAND ON L ATTEINT
sec
lda PTR_STACK
sbc #<STACK_ADDR
pha
lda PTR_STACK+1
sbc #>STACK_ADDR
lsr
sta SIZE_STACK+1
pla
ror
sta SIZE_STACK
; # Opening the first door
lda #0
sta NB_DOORS
lda #<STACK_ADDR
sta PTR_STACK ; here stack size < 128, no need for hsb of the address
loop_first_door:
jsr Random8
ldx SIZE_STACK
jsr Modulus
asl
tay
lda (PTR_STACK), Y
;PTR_TILE = *PTR_STACK - WIDTH_WORLD
sec
sbc #WIDTH_WORLD
sta PTR_TILE
iny
lda (PTR_STACK), Y
sbc #0
sta PTR_TILE+1
jsr _nb_walkable
lda NB_WALKABLE
cmp #2
bcc loop_first_door ; nb_walkable < 2
inc NB_DOORS
ldy #WIDTH_WORLD
lda #eACTORTYPES::FLOOR_1
sta (PTR_TILE), Y
; # Opening the other doors
.define IDX ZERO_2_3
lda #<STACK_ADDR
sta PTR_STACK ; here stack size < 128, no need for hsb of the address
lda #$FF
sta IDX
loop_other_doors:
inc IDX
; test if end
lda SIZE_STACK
asl
cmp IDX
beq end_loop_other_doors
; random number to be compare to the probability of a door
jsr Random8
cmp PROBABILITY_OPENING
bcc test_door
beq test_door
inc IDX
bcs loop_other_doors ; always jump as the previous bcc failed
; test if the tile can be linked to the maze
test_door:
ldy IDX
lda (PTR_STACK), Y
;PTR_TILE = *PTR_STACK - WIDTH_WORLD
sec
sbc #WIDTH_WORLD
sta PTR_TILE
iny
lda (PTR_STACK), Y
sbc #0
sta PTR_TILE+1
sty IDX
jsr _nb_walkable
lda NB_WALKABLE
cmp #2
bcs carve_a_door
bcc loop_other_doors ; always jump as the previous bcs failed
carve_a_door:
ldy #WIDTH_WORLD
lda #eACTORTYPES::FLOOR_1
sta (PTR_TILE), Y
inc NB_DOORS
jmp loop_other_doors
end_loop_other_doors:
dec NB_ROOMS
beq end_loop_connect_rooms
; next room
lda OFFSET_ROOMS
clc
adc #.sizeof(Config_Room)
sta OFFSET_ROOMS
jmp loop_connect_rooms
end_loop_connect_rooms:
rts
; @brief returns the number of walkable neighbours. >= 2 if it can be carved
; @detailed PTR_TILE is offsetted by -WIDTH_WORLD
_nb_walkable:
lda #0
sta NB_WALKABLE
lda #eACTORTYPES::FLOOR_1
tst_up:
ldy #0
cmp (PTR_TILE), Y
bne tst_left
inc NB_WALKABLE
tst_left:
ldy #(WIDTH_WORLD-1)
cmp (PTR_TILE), Y
bne tst_right
inc NB_WALKABLE
tst_right:
ldy #(WIDTH_WORLD+1)
cmp (PTR_TILE), Y
bne tst_down
inc NB_WALKABLE
tst_down:
ldy #(2*WIDTH_WORLD)
cmp (PTR_TILE), Y
bne end_is_door_possible
inc NB_WALKABLE
end_is_door_possible:
rts
.undefine STACK_ADDR
.undefine PTR_TILE_TOP
.undefine PTR_TILE_BOT
.undefine PTR_TILE_LEFT
.undefine PTR_TILE_RIGHT
.undefine PTR_TILE
.undefine PTR_STACK
.undefine PROBABILITY_OPENING
.undefine NB_DOORS
.undefine NB_WALKABLE
.undefine SIZE_STACK
.undefine WIDTH_ROOM
.undefine HEIGHT_ROOM
.undefine OFFSET_ROOMS

20
src/builder/rooms.inc Normal file
View File

@ -0,0 +1,20 @@
; Copyright (C) 2019 Christophe Meneboeuf <christophe@xtof.info>
;
; This program is free software: you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
; the Free Software Foundation, either version 3 of the License, or
; (at your option) any later version.
;
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
; GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public License
; along with this program. If not, see <http://www.gnu.org/licenses/>.
.import Carve_Rooms
.import Connect_Rooms
.define MAX_NB_ROOMS 64 ; MAX_NB_ROOMS *MUST BE* <= 64 and a power of 2

561
src/builder/unite.asm Normal file
View File

@ -0,0 +1,561 @@
; Copyright (C) 2020 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 "rooms.inc"
.include "maze.inc"
.include "../io/textio.inc"
.include "../memory.inc"
.include "../math.inc"
.include "../common.inc"
.include "../world/world.inc"
.include "../actors/actors.inc"
.import World
.import Rooms
.import WIDTH_MAZE
.import HEIGHT_MAZE
.import Compute_Maze_Addr
.export Unite_Rooms
.CODE
.define PTR_TILE ZERO_2_1 ; 2 bytes
.define ZONE_NR ZERO_2_4
.define CPT_X ZERO_2_5
.define CPT_Y ZERO_2_6
.define QUEUE_ADDR $4000
.define REPLACED_NR ZERO_3
.define PTR_QUEUE ZERO_4_1 ; 2 bytes
.define PTR_TILE_LOCAL ZERO_4_3 ; 2 bytes
.define FILL_NR ZERO_4_5
; @param X fill color
; @param A replaced
; @return TRUE in A some tiles were filled, FALSE otherwise
_Flood_Fill :
stx FILL_NR
ldy #0
cmp (PTR_TILE), Y ; if (*ptr_tile != replaced) return;
beq fill_1
lda #FALSE
rts
fill_1:
sta REPLACED_NR
txa
sta (PTR_TILE), Y
lda #<QUEUE_ADDR
sta PTR_QUEUE
lda #>QUEUE_ADDR
sta PTR_QUEUE+1
; offset ptr_tile by -width_world to be quickly accessed with an Y offset
lda PTR_TILE
sec
sbc #WIDTH_WORLD
sta QUEUE_ADDR
lda PTR_TILE+1
sbc #0
sta QUEUE_ADDR+1
ldx #0
loop_fill:
; while ptr_queue >= QUEUE_ADDR
lda PTR_QUEUE
cmp #<(QUEUE_ADDR-2)
bne continue_fill
lda PTR_QUEUE+1
cmp #>(QUEUE_ADDR-2)
bne continue_fill
jmp end_fill
continue_fill:
; ptr_tile = *(ptr_queue--);
ldy #0
lda (PTR_QUEUE), Y
sta PTR_TILE_LOCAL
iny
lda (PTR_QUEUE), Y
sta PTR_TILE_LOCAL+1
DEC16 PTR_QUEUE, #2
tile_west:
; if (*tile_west == replaced)
ldy #(WIDTH_WORLD+1)
lda REPLACED_NR
cmp (PTR_TILE_LOCAL),Y
bne tile_east
; *tile_west = fill;
lda FILL_NR
sta (PTR_TILE_LOCAL),Y
; *(++ptr_queue) = tile_w
ADD16 PTR_QUEUE, #2, #0
clc
lda #1
adc PTR_TILE_LOCAL
ldy #0
sta (PTR_QUEUE),Y
lda #0
adc PTR_TILE_LOCAL+1
iny
sta (PTR_QUEUE),Y
tile_east:
; if (*tile_east == replaced)
ldy #(WIDTH_WORLD-1)
lda REPLACED_NR
cmp (PTR_TILE_LOCAL),Y
bne tile_north
; *tile_east = fill;
lda FILL_NR
sta (PTR_TILE_LOCAL),Y
; *(++ptr_queue) = tile_tile_east
ADD16 PTR_QUEUE, #2, #0
sec
lda PTR_TILE_LOCAL
sbc #1
ldy #0
sta (PTR_QUEUE),Y
lda PTR_TILE_LOCAL+1
sbc #0
iny
sta (PTR_QUEUE),Y
tile_north:
; if (*tile_north == replaced)
ldy #0
lda REPLACED_NR
cmp (PTR_TILE_LOCAL),Y
bne tile_south
; *tile_north = fill;
lda FILL_NR
sta (PTR_TILE_LOCAL),Y
; *(++ptr_queue) = tile_tile_north
ADD16 PTR_QUEUE, #2, #0
sec
lda PTR_TILE_LOCAL
sbc #WIDTH_WORLD
ldy #0
sta (PTR_QUEUE),Y
lda PTR_TILE_LOCAL+1
sbc #0
iny
sta (PTR_QUEUE),Y
tile_south:
; if (*tile_south == replaced)
ldy #(2*WIDTH_WORLD)
lda REPLACED_NR
cmp (PTR_TILE_LOCAL),Y
bne end_tiles
; *tile_south = fill;
lda FILL_NR
sta (PTR_TILE_LOCAL),Y
; *(++ptr_queue) = tile_tile_south
ADD16 PTR_QUEUE, #2, #0
clc
lda #WIDTH_WORLD
adc PTR_TILE_LOCAL
ldy #0
sta (PTR_QUEUE),Y
lda #0
adc PTR_TILE_LOCAL+1
iny
sta (PTR_QUEUE),Y
end_tiles:
jmp loop_fill
end_fill:
lda #TRUE
rts
.define ROOM_NR ZERO_3
.define SAVE_X ZERO_4_1
.define PTR_ROOM ZERO_4_2 ; 2 bytes
.define ZONE_0 eACTORTYPES::FLOOR_1 ; 1st useful zone: ZONE_1
Unite_Rooms:
; *** flood fill room to identify separated zones ***
; &Wordl[1][1] -> ptr_tile
clc
lda #<World
adc #WIDTH_WORLD+1
sta PTR_TILE
lda #>World
adc #0
sta PTR_TILE+1
lda #1
sta CPT_X
sta CPT_Y
lda #ZONE_0
sta ZONE_NR
inc ZONE_NR
loop_flood:
ldx ZONE_NR
lda #ZONE_0
jsr _Flood_Fill
cmp #TRUE
bne loop_flood_next
inc ZONE_NR
loop_flood_next:
;next tile
ADD16 PTR_TILE, #1, #0
; end line?
inc CPT_X
ldx CPT_X
cpx #WIDTH_WORLD-1
bne loop_flood
ldx #0
stx CPT_X
; next
ADD16 PTR_TILE, #1, #0
; the end?
inc CPT_Y
ldy CPT_Y
cpy #HEIGHT_WORLD-1
bne loop_flood
; ***
; reunite rooms that are not in the first zone
; find the location of a room in zone_1
; Its origin will be targeted by th other zones to join
; ***
.define SIZEOF_ROOM_T 4
.define ROOM_ZONE_1 ZERO_5_4
lda #0 ; FIXEME : useless?
sta ROOM_NR ; FIXEME : useless?
ldx #3
lda #WIDTH_WORLD
sta FAC2
loop_find_room:
lda Rooms, X
tay
stx SAVE_X
dex
lda Rooms, X
tax
jsr Compute_Maze_Addr
sta PTR_TILE+1
stx PTR_TILE
ldy #0
lda (PTR_TILE), Y
cmp #(ZONE_0 + 1)
beq room_found
; next room
lda SAVE_X
clc
adc #(SIZEOF_ROOM_T)
tax
jmp loop_find_room
room_found:
ldx SAVE_X
stx ROOM_ZONE_1
; ***
; Connect one room of each zone to the location found
.define END_LOOP_ZONE ZERO_5_1
lda ZONE_NR
sta END_LOOP_ZONE
lda #(ZONE_0 + 2) ; zone_2
cmp END_LOOP_ZONE
beq end_loop_zone ; only one zone
sta ZONE_NR
; loop over the zones
loop_zones:
ldx #3
loop_rooms: ; find a room of the zone
lda Rooms, X
tay
stx SAVE_X
dex
lda Rooms, X
tax
jsr Compute_Maze_Addr
stx ZERO_5_2
sta ZERO_5_3
ldy #0
lda (ZERO_5_2), Y
cmp ZONE_NR
beq zone_found
; next room
lda SAVE_X
clc
adc #(SIZEOF_ROOM_T)
tax
jmp loop_rooms
zone_found:
jsr _Connect_Room
; next zone
inc ZONE_NR
; end loop?
lda END_LOOP_ZONE
cmp ZONE_NR
beq end_loop_zone
; loop
jmp loop_zones
end_loop_zone:
rts
; to compute ptr_romm += ix / iy or ptr_romm += ix / iy, the code is patched.
.macro PATCH_POS address, address2
lda #$18 ; clc
sta address
sta address2
lda #$69 ; adc imm
sta address+3 ; adc #1 / #WIDTH_WORLD
sta address+9 ; adc #0
sta address2+3 ; adc #1 / #WIDTH_WORLD
sta address2+9 ; adc #0
.endmacro
.macro PATCH_NEG address, address2
lda #$38 ; sec
sta address
sta address2
lda #$E9 ; sbc imm
sta address+3 ; sbc #1 / #WIDTH_WORLD
sta address+9 ; sbc #0
sta address2+3 ; sbc #1 / #WIDTH_WORLD
sta address2+9 ; sbc #0
.endmacro
.define DELTA_X ZERO_9_1
.define DELTA_Y ZERO_9_2
.define DELTA_X_2 ZERO_9_3
.define DELTA_Y_2 ZERO_9_4
.define ROOM_Y ZERO_9_5
.define ROOM_X ZERO_9_6
.define D ZERO_9_7
.define ROOM_FOUND SAVE_X
_Connect_Room:
; d = 0
lda #0
sta D
; delta_y = zone1_y - room->y
ldx ROOM_FOUND
lda Rooms, X
sta ROOM_Y ; room->y
dex
lda Rooms, X
sta ROOM_X ; room->x
ldx ROOM_ZONE_1
lda Rooms, X ; zone1_y
sec
sbc ROOM_Y
sta DELTA_Y
; delta_x = zone1_x - room->x
dex
lda Rooms, X ; zone1_x
sec
sbc ROOM_X
sta DELTA_X
; delta_x = delta_x > 0 ? delta_x : -delta_x
lda #0
cmp DELTA_X
bmi end_abs_x
sec
sbc DELTA_X
sta DELTA_X
end_abs_x:
; int dx2 = 2 * dx
lda DELTA_X
asl
sta DELTA_X_2
; delta_y = delta_y > 0 ? delta_y : -delta_y
abs_delta_y:
lda #0
cmp DELTA_Y
bmi end_abs_y
sec
sbc DELTA_Y
sta DELTA_Y
end_abs_y:
; int dy2 = 2 * dy
lda DELTA_Y
asl
sta DELTA_Y_2
; uint8_t* ptr_room = &World[room->y][room->x]
ldx ROOM_X
ldy ROOM_Y
jsr Compute_Maze_Addr
stx PTR_ROOM
stx PTR_TILE
sta PTR_ROOM+1
sta PTR_TILE+1
ldx ROOM_ZONE_1
dex
; int ix = room->x < zone1_x ? 1 : -1
ix:
lda ROOM_X
cmp Rooms, X
bcc ix_positive
PATCH_NEG patch_ix1, patch_ix2
jmp iy
ix_positive:
PATCH_POS patch_ix1, patch_ix2
; int iy = room->y < zone1_y ? WIDTH_WORLD : -WIDTH_WORLD;
iy:
inx
lda ROOM_Y
cmp Rooms, X
bcc iy_positive
PATCH_NEG patch_iy1, patch_iy2
jmp iterate
iy_positive:
PATCH_POS patch_iy1, patch_iy2
iterate:
ldy #0
lda DELTA_X
cmp DELTA_Y
bcc dy_sup
; if (dx >= dy)
dx_sup:
while_1:
; ptr_room += ix
patch_ix1:
ADD16 PTR_ROOM, #1, #0
; d += dy2
clc
lda DELTA_Y_2
adc D
sta D
cmp DELTA_X
bcc d_infequal_dx
beq d_infequal_dx
; if (d > dx)
; if (*ptr_room != zone_nr && *ptr_room <= WALKABLE) break;
lda (PTR_ROOM), Y ; Y = 0
cmp ZONE_NR
beq continue_1a
cmp #eACTORTYPES::LAST_FLOOR
beq end
bpl continue_1a
jmp end
continue_1a:
; *ptr_room = zone_nr
lda ZONE_NR
sta (PTR_ROOM), Y ; Y = 0
; ptr_room += iy
patch_iy1:
ADD16 PTR_ROOM, #WIDTH_WORLD, #0
; d -= dx2
sec
lda D
sbc DELTA_X_2
sta D
d_infequal_dx:
; if (*ptr_room != zone_nr && *ptr_room <= WALKABLE) break;
lda (PTR_ROOM), Y ; Y = 0
cmp ZONE_NR
beq continue_1b
cmp #eACTORTYPES::LAST_FLOOR
beq end
bpl continue_1b
jmp end
continue_1b:
lda ZONE_NR
sta (PTR_ROOM), Y ; Y = 0
jmp while_1
; end label in the middle to be reachable by the branches
end:
; flood fills works on ptr_tile
ldx #(ZONE_0 + 1)
lda ZONE_NR
jsr _Flood_Fill
rts
dy_sup:
while_2:
; ptr_room += iy
patch_iy2:
ADD16 PTR_ROOM, #WIDTH_WORLD, #0
; d += dx2
clc
lda DELTA_X_2
adc D
sta D
cmp DELTA_Y
bcc d_infequal_dy
beq d_infequal_dy
; if (d > dy) {
; if (*ptr_room != zone_nr && *ptr_room <= WALKABLE) break;
lda (PTR_ROOM), Y ; Y = 0
cmp ZONE_NR
beq continue_2a
cmp #eACTORTYPES::LAST_FLOOR
beq end
bpl continue_2a
jmp end
continue_2a:
; *ptr_room = zone_nr
lda ZONE_NR
sta (PTR_ROOM), Y ; Y = 0
; ptr_room += ix;
patch_ix2:
ADD16 PTR_ROOM, #1, #0
; d -= dy2
sec
lda D
sbc DELTA_Y_2
sta D
d_infequal_dy:
; (*ptr_room != zone_nr && *ptr_room <= WALKABLE)
lda (PTR_ROOM), Y ; Y = 0
cmp ZONE_NR
beq continue_2b
cmp #eACTORTYPES::LAST_FLOOR
beq end
bpl continue_2b
jmp end
continue_2b:
lda ZONE_NR
sta (PTR_ROOM), Y ; Y = 0
jmp while_2

16
src/builder/unite.inc Normal file
View File

@ -0,0 +1,16 @@
; Copyright (C) 2020 Christophe Meneboeuf <christophe@xtof.info>
;
; This program is free software: you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
; the Free Software Foundation, either version 3 of the License, or
; (at your option) any later version.
;
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
; GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public License
; along with this program. If not, see <http://www.gnu.org/licenses/>.
.import Unite_Rooms

18
src/common.inc Normal file
View File

@ -0,0 +1,18 @@
; Copyright (C) 2020 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/>.
.define TRUE 1
.define FALSE 0
.define UNDEF $FF

View File

@ -1,8 +1,28 @@
; Copyright (C) 2020 Christophe Meneboeuf <christophe@xtof.info>
;
; This program is free software: you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
; the Free Software Foundation, either version 3 of the License, or
; (at your option) any later version.
;
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
; GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public License
; along with this program. If not, see <http://www.gnu.org/licenses/>.
.include "memory.inc"
; nb of bytes to be displayed in DBG_TRACES[0]
.export DBG_TRACE
; bytes to be displayed
.export DBG_TRACES
.CODE
.define STROUT $DB3A ; Applesoft: OUTPUTS AY-POINTED NULL TERMINATED STRING
.define LINPTR $ED24 ; Applesoft: Displays the number A(high)X(low) in decimal
@ -39,3 +59,6 @@ str_space: .byte " ", 0
.BSS
DBG_TRACES: .res 7 ; bytes to be displayed by TRACE

View File

@ -14,13 +14,14 @@
; 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/world.inc"
.include "actors/actors.inc"
.include "display.inc"
.include "world.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!
@ -42,9 +43,11 @@
; X: TILE_COORD_X
; Y: TILE_COORD_Y
.import compute_maze_addr
.import Compute_Maze_Addr
.import World
.import Player_XY
.import ActorTransparent
.import ActorTypes
.import DBG_TRACE
.import DBG_TRACES
@ -97,6 +100,7 @@ loop_view_init:
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
@ -106,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
@ -115,17 +119,18 @@ _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
.define NB_RAYS 36
.define NB_RAYS 68
.define NB_ITER ZERO_4_3
.define NB_TILES_IN_RAY ZERO_4_4
.define NB_TILES_IN_RAY_LEFT ZERO_5_1
.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
@ -183,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
@ -249,6 +260,7 @@ view_refresh:
; 3 - build the view to be displayed
jsr _build_view
;jsr _dbg_build_view
; 4 - display the tiles viewed
.define SAVE_X ZERO_3
@ -282,7 +294,7 @@ loop_display_tiles_y:
rts
.undef VIEW_WORLD
SHIFT_VIEW: .word WIDTH_MAZE*PLAYER_Y + PLAYER_X ; shift to center the view on the player
SHIFT_VIEW: .word WIDTH_WORLD*PLAYER_Y + PLAYER_X ; shift to center the view on the player
.CODE
set_view_coords:
@ -290,7 +302,7 @@ set_view_coords:
; 1. Compute offset from the starting address of the maze
stx ZERO_2_1
sty FAC1
lda #WIDTH_MAZE
lda #WIDTH_WORLD
sta FAC2
jsr mul8
tay ; high part
@ -437,7 +449,7 @@ PATCH_8:
.DATA
.RODATA
; Adress of the tiles in the HIRES screen
; T0 T1 T2
@ -454,45 +466,77 @@ HGR_GRID:
.word $2050, $2054, $2058, $205C, $2060, $2064, $2068, $206C, $2070, $2074
.word $2150, $2154, $2158, $215C, $2160, $2164, $2168, $216C, $2170, $2174
; Nb rays: 36
; Nb rays: 68
; A ray: length (nb_tiles), offset_from_view_in_world_low, offset_from_view_in_world_high, offset_view
Rays:
.byte 5, 4, 1, 44, 195, 0, 33, 130, 0, 22, 65, 0, 11, 0, 0, 0
.byte 5, 4, 1, 44, 195, 0, 33, 131, 0, 23, 66, 0, 12, 1, 0, 1
.byte 5, 4, 1, 44, 196, 0, 34, 131, 0, 23, 67, 0, 13, 2, 0, 2
.byte 5, 5, 1, 45, 196, 0, 34, 132, 0, 24, 67, 0, 13, 3, 0, 3
.byte 5, 5, 1, 45, 197, 0, 35, 132, 0, 24, 68, 0, 14, 4, 0, 4
.byte 10, 68, 1, 54, 4, 1, 44, 3, 1, 43, 195, 0, 33, 194, 0, 32, 130, 0, 22, 129, 0, 21, 65, 0, 11, 64, 0, 10, 0, 0, 0
.byte 10, 5, 1, 45, 4, 1, 44, 196, 0, 34, 195, 0, 33, 131, 0, 23, 130, 0, 22, 66, 0, 12, 65, 0, 11, 1, 0, 1, 0, 0, 0
.byte 9, 68, 1, 54, 4, 1, 44, 3, 1, 43, 195, 0, 33, 131, 0, 23, 130, 0, 22, 66, 0, 12, 65, 0, 11, 1, 0, 1
.byte 9, 5, 1, 45, 4, 1, 44, 196, 0, 34, 195, 0, 33, 131, 0, 23, 67, 0, 13, 66, 0, 12, 2, 0, 2, 1, 0, 1
.byte 8, 68, 1, 54, 4, 1, 44, 196, 0, 34, 195, 0, 33, 131, 0, 23, 67, 0, 13, 66, 0, 12, 2, 0, 2
.byte 8, 5, 1, 45, 4, 1, 44, 196, 0, 34, 132, 0, 24, 131, 0, 23, 67, 0, 13, 3, 0, 3, 2, 0, 2
.byte 7, 5, 1, 45, 4, 1, 44, 196, 0, 34, 132, 0, 24, 131, 0, 23, 67, 0, 13, 3, 0, 3
.byte 7, 5, 1, 45, 197, 0, 35, 196, 0, 34, 132, 0, 24, 68, 0, 14, 67, 0, 13, 3, 0, 3
.byte 6, 5, 1, 45, 197, 0, 35, 196, 0, 34, 132, 0, 24, 68, 0, 14, 4, 0, 4
.byte 6, 5, 1, 45, 197, 0, 35, 133, 0, 25, 132, 0, 24, 68, 0, 14, 4, 0, 4
.byte 5, 5, 1, 45, 197, 0, 35, 133, 0, 25, 69, 0, 15, 5, 0, 5
.byte 5, 5, 1, 45, 197, 0, 35, 134, 0, 26, 70, 0, 16, 6, 0, 6
.byte 5, 5, 1, 45, 198, 0, 36, 134, 0, 26, 71, 0, 17, 7, 0, 7
.byte 5, 6, 1, 46, 198, 0, 36, 135, 0, 27, 71, 0, 17, 8, 0, 8
.byte 5, 6, 1, 46, 199, 0, 37, 135, 0, 27, 72, 0, 18, 9, 0, 9
.byte 4, 6, 1, 46, 199, 0, 37, 136, 0, 28, 73, 0, 19
.byte 4, 6, 1, 46, 199, 0, 37, 200, 0, 38, 137, 0, 29
.byte 4, 6, 1, 46, 7, 1, 47, 200, 0, 38, 201, 0, 39
.byte 4, 70, 1, 56, 7, 1, 47, 8, 1, 48, 9, 1, 49
.byte 6, 5, 1, 45, 197, 0, 35, 198, 0, 36, 134, 0, 26, 70, 0, 16, 6, 0, 6
.byte 6, 5, 1, 45, 197, 0, 35, 133, 0, 25, 134, 0, 26, 70, 0, 16, 6, 0, 6
.byte 7, 5, 1, 45, 6, 1, 46, 198, 0, 36, 134, 0, 26, 135, 0, 27, 71, 0, 17, 7, 0, 7
.byte 7, 5, 1, 45, 197, 0, 35, 198, 0, 36, 134, 0, 26, 70, 0, 16, 71, 0, 17, 7, 0, 7
.byte 8, 70, 1, 56, 6, 1, 46, 198, 0, 36, 199, 0, 37, 135, 0, 27, 71, 0, 17, 72, 0, 18, 8, 0, 8
.byte 8, 5, 1, 45, 6, 1, 46, 198, 0, 36, 134, 0, 26, 135, 0, 27, 71, 0, 17, 7, 0, 7, 8, 0, 8
.byte 9, 70, 1, 56, 6, 1, 46, 7, 1, 47, 199, 0, 37, 135, 0, 27, 136, 0, 28, 72, 0, 18, 73, 0, 19, 9, 0, 9
.byte 9, 5, 1, 45, 6, 1, 46, 198, 0, 36, 199, 0, 37, 135, 0, 27, 71, 0, 17, 72, 0, 18, 8, 0, 8, 9, 0, 9
.byte 8, 70, 1, 56, 6, 1, 46, 7, 1, 47, 199, 0, 37, 200, 0, 38, 136, 0, 28, 137, 0, 29, 73, 0, 19
.byte 8, 5, 1, 45, 6, 1, 46, 198, 0, 36, 199, 0, 37, 135, 0, 27, 136, 0, 28, 72, 0, 18, 73, 0, 19
.byte 7, 70, 1, 56, 6, 1, 46, 7, 1, 47, 199, 0, 37, 200, 0, 38, 201, 0, 39, 137, 0, 29
.byte 7, 5, 1, 45, 6, 1, 46, 198, 0, 36, 199, 0, 37, 200, 0, 38, 136, 0, 28, 137, 0, 29
.byte 6, 70, 1, 56, 6, 1, 46, 7, 1, 47, 8, 1, 48, 200, 0, 38, 201, 0, 39
.byte 6, 5, 1, 45, 6, 1, 46, 7, 1, 47, 199, 0, 37, 200, 0, 38, 201, 0, 39
.byte 5, 70, 1, 56, 71, 1, 57, 7, 1, 47, 8, 1, 48, 9, 1, 49
.byte 5, 70, 1, 56, 6, 1, 46, 7, 1, 47, 8, 1, 48, 9, 1, 49
.byte 4, 70, 1, 56, 71, 1, 57, 72, 1, 58, 73, 1, 59
.byte 4, 70, 1, 56, 135, 1, 67, 136, 1, 68, 137, 1, 69
.byte 4, 134, 1, 66, 135, 1, 67, 200, 1, 78, 201, 1, 79
.byte 4, 134, 1, 66, 199, 1, 77, 200, 1, 78, 9, 2, 89
.byte 4, 134, 1, 66, 199, 1, 77, 8, 2, 88, 73, 2, 99
.byte 4, 134, 1, 66, 199, 1, 77, 7, 2, 87, 72, 2, 98
.byte 4, 134, 1, 66, 198, 1, 76, 7, 2, 87, 71, 2, 97
.byte 4, 133, 1, 65, 198, 1, 76, 6, 2, 86, 70, 2, 96
.byte 5, 70, 1, 56, 71, 1, 57, 135, 1, 67, 136, 1, 68, 137, 1, 69
.byte 5, 70, 1, 56, 134, 1, 66, 135, 1, 67, 136, 1, 68, 137, 1, 69
.byte 6, 70, 1, 56, 134, 1, 66, 135, 1, 67, 136, 1, 68, 200, 1, 78, 201, 1, 79
.byte 6, 133, 1, 65, 134, 1, 66, 135, 1, 67, 199, 1, 77, 200, 1, 78, 201, 1, 79
.byte 7, 70, 1, 56, 134, 1, 66, 135, 1, 67, 199, 1, 77, 200, 1, 78, 201, 1, 79, 9, 2, 89
.byte 7, 133, 1, 65, 134, 1, 66, 198, 1, 76, 199, 1, 77, 200, 1, 78, 8, 2, 88, 9, 2, 89
.byte 8, 70, 1, 56, 134, 1, 66, 135, 1, 67, 199, 1, 77, 200, 1, 78, 8, 2, 88, 9, 2, 89, 73, 2, 99
.byte 8, 133, 1, 65, 134, 1, 66, 198, 1, 76, 199, 1, 77, 7, 2, 87, 8, 2, 88, 72, 2, 98, 73, 2, 99
.byte 7, 70, 1, 56, 134, 1, 66, 135, 1, 67, 199, 1, 77, 7, 2, 87, 8, 2, 88, 72, 2, 98
.byte 7, 133, 1, 65, 134, 1, 66, 198, 1, 76, 199, 1, 77, 7, 2, 87, 71, 2, 97, 72, 2, 98
.byte 6, 70, 1, 56, 134, 1, 66, 198, 1, 76, 199, 1, 77, 7, 2, 87, 71, 2, 97
.byte 6, 133, 1, 65, 134, 1, 66, 198, 1, 76, 6, 2, 86, 7, 2, 87, 71, 2, 97
.byte 5, 133, 1, 65, 134, 1, 66, 198, 1, 76, 6, 2, 86, 70, 2, 96
.byte 5, 133, 1, 65, 197, 1, 75, 198, 1, 76, 6, 2, 86, 70, 2, 96
.byte 4, 133, 1, 65, 197, 1, 75, 5, 2, 85, 69, 2, 95
.byte 4, 133, 1, 65, 196, 1, 74, 4, 2, 84, 68, 2, 94
.byte 4, 132, 1, 64, 196, 1, 74, 3, 2, 83, 67, 2, 93
.byte 4, 132, 1, 64, 195, 1, 73, 3, 2, 83, 66, 2, 92
.byte 4, 132, 1, 64, 195, 1, 73, 2, 2, 82, 65, 2, 91
.byte 5, 132, 1, 64, 195, 1, 73, 194, 1, 72, 1, 2, 81, 64, 2, 90
.byte 5, 132, 1, 64, 131, 1, 63, 194, 1, 72, 193, 1, 71, 0, 2, 80
.byte 5, 68, 1, 54, 131, 1, 63, 130, 1, 62, 193, 1, 71, 192, 1, 70
.byte 5, 68, 1, 54, 67, 1, 53, 130, 1, 62, 129, 1, 61, 128, 1, 60
.byte 5, 133, 1, 65, 132, 1, 64, 196, 1, 74, 4, 2, 84, 68, 2, 94
.byte 5, 133, 1, 65, 197, 1, 75, 196, 1, 74, 4, 2, 84, 68, 2, 94
.byte 6, 68, 1, 54, 132, 1, 64, 196, 1, 74, 195, 1, 73, 3, 2, 83, 67, 2, 93
.byte 6, 133, 1, 65, 132, 1, 64, 196, 1, 74, 4, 2, 84, 3, 2, 83, 67, 2, 93
.byte 7, 68, 1, 54, 132, 1, 64, 131, 1, 63, 195, 1, 73, 3, 2, 83, 2, 2, 82, 66, 2, 92
.byte 7, 133, 1, 65, 132, 1, 64, 196, 1, 74, 195, 1, 73, 3, 2, 83, 67, 2, 93, 66, 2, 92
.byte 8, 68, 1, 54, 132, 1, 64, 131, 1, 63, 195, 1, 73, 194, 1, 72, 2, 2, 82, 1, 2, 81, 65, 2, 91
.byte 8, 133, 1, 65, 132, 1, 64, 196, 1, 74, 195, 1, 73, 3, 2, 83, 2, 2, 82, 66, 2, 92, 65, 2, 91
.byte 9, 68, 1, 54, 132, 1, 64, 131, 1, 63, 195, 1, 73, 194, 1, 72, 193, 1, 71, 1, 2, 81, 0, 2, 80, 64, 2, 90
.byte 9, 133, 1, 65, 132, 1, 64, 196, 1, 74, 195, 1, 73, 194, 1, 72, 2, 2, 82, 1, 2, 81, 65, 2, 91, 64, 2, 90
.byte 8, 68, 1, 54, 132, 1, 64, 131, 1, 63, 130, 1, 62, 194, 1, 72, 193, 1, 71, 192, 1, 70, 0, 2, 80
.byte 8, 133, 1, 65, 132, 1, 64, 131, 1, 63, 195, 1, 73, 194, 1, 72, 193, 1, 71, 1, 2, 81, 0, 2, 80
.byte 7, 68, 1, 54, 67, 1, 53, 131, 1, 63, 130, 1, 62, 129, 1, 61, 193, 1, 71, 192, 1, 70
.byte 7, 68, 1, 54, 132, 1, 64, 131, 1, 63, 130, 1, 62, 194, 1, 72, 193, 1, 71, 192, 1, 70
.byte 6, 68, 1, 54, 67, 1, 53, 66, 1, 52, 130, 1, 62, 129, 1, 61, 128, 1, 60
.byte 6, 68, 1, 54, 67, 1, 53, 131, 1, 63, 130, 1, 62, 129, 1, 61, 128, 1, 60
.byte 5, 68, 1, 54, 67, 1, 53, 66, 1, 52, 65, 1, 51, 64, 1, 50
.byte 5, 68, 1, 54, 67, 1, 53, 2, 1, 42, 1, 1, 41, 0, 1, 40
.byte 5, 68, 1, 54, 3, 1, 43, 2, 1, 42, 193, 0, 31, 192, 0, 30
.byte 5, 4, 1, 44, 3, 1, 43, 194, 0, 32, 193, 0, 31, 128, 0, 20
.byte 5, 4, 1, 44, 195, 0, 33, 194, 0, 32, 129, 0, 21, 64, 0, 10
.byte 6, 68, 1, 54, 67, 1, 53, 66, 1, 52, 2, 1, 42, 1, 1, 41, 0, 1, 40
.byte 6, 68, 1, 54, 67, 1, 53, 3, 1, 43, 2, 1, 42, 1, 1, 41, 0, 1, 40
.byte 7, 68, 1, 54, 67, 1, 53, 3, 1, 43, 2, 1, 42, 1, 1, 41, 193, 0, 31, 192, 0, 30
.byte 7, 68, 1, 54, 4, 1, 44, 3, 1, 43, 2, 1, 42, 194, 0, 32, 193, 0, 31, 192, 0, 30
.byte 8, 68, 1, 54, 4, 1, 44, 3, 1, 43, 2, 1, 42, 194, 0, 32, 193, 0, 31, 192, 0, 30, 128, 0, 20
.byte 8, 5, 1, 45, 4, 1, 44, 3, 1, 43, 195, 0, 33, 194, 0, 32, 193, 0, 31, 129, 0, 21, 128, 0, 20
.byte 9, 68, 1, 54, 4, 1, 44, 3, 1, 43, 195, 0, 33, 194, 0, 32, 193, 0, 31, 129, 0, 21, 128, 0, 20, 64, 0, 10
.byte 9, 5, 1, 45, 4, 1, 44, 196, 0, 34, 195, 0, 33, 194, 0, 32, 130, 0, 22, 129, 0, 21, 65, 0, 11, 64, 0, 10
.BSS

341
src/display_map.asm Normal file
View File

@ -0,0 +1,341 @@
; Copyright (C) 2019 Christophe Meneboeuf <christophe@xtof.info>
;
; This program is free software: you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
; the Free Software Foundation, either version 3 of the License, or
; (at your option) any later version.
;
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
; GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public License
; along with this program. If not, see <http://www.gnu.org/licenses/>.
.include "world/world.inc"
.include "actors/actors.inc"
.include "io/gr.inc"
.include "memory.inc"
.include "math.inc"
.include "monitor.inc"
; inits display of map
.export Display_Map_Init
; displays the map and reacts to keyboard input
.export Map_Loop
; displays the map
.export Display_Map_Show
.define DBG_DISP_WIDTH 40
.define DBG_DISP_HEIGHT 48
.BSS
Map_x: .byte 1
Map_y: .byte 1
.define MAX_Y HEIGHT_WORLD - DBG_DISP_HEIGHT
.define MAX_X WIDTH_WORLD - DBG_DISP_WIDTH
.CODE
.define KEY_UP $C9
.define KEY_LEFT $CA
.define KEY_DOWN $CB
.define KEY_RIGHT $CC
.define TAB $89
; ##################### MAP ##################
; Buffer to save the 4 bottom line of gr1
SAVED_GR_L36: .res 40
SAVED_GR_L37: .res 40
SAVED_GR_L38: .res 40
SAVED_GR_L39: .res 40
; The 4 bottom lines of GR1
.define SRC_GR1_L36 $650
.define SRC_GR1_L37 $6D0
.define SRC_GR1_L38 $750
.define SRC_GR1_L39 $7D0
; @brief Displays the map and wait for action: move the view or exit
Map_Loop:
; save the 4 last lines of GR1
ldx #39
loop_save_gr:
lda SRC_GR1_L36, X
sta SAVED_GR_L36, X
lda SRC_GR1_L37, X
sta SAVED_GR_L37, X
lda SRC_GR1_L38, X
sta SAVED_GR_L38, X
lda SRC_GR1_L39, X
sta SAVED_GR_L39, X
dex
bne loop_save_gr
lda SRC_GR1_L36, X
sta SAVED_GR_L36, X
lda SRC_GR1_L37, X
sta SAVED_GR_L37, X
lda SRC_GR1_L38, X
sta SAVED_GR_L38, X
lda SRC_GR1_L39, X
sta SAVED_GR_L39, X
disp:
; display map
;sta $C051 ; full screen
sta $C054 ; page 1
sta $C056 ; lores
sta $C050 ; gfx
sta $C052 ; mixed mode off
ldx Map_x
ldy Map_y
; capping X and Y
min_x:
cpx #$FF
bne max_x
ldx #0
bvc min_y
max_x:
cpx #MAX_X
bcc min_y
ldx #MAX_X
min_y:
cpy #$FF
bne max_y
ldy #0
bvc disp_map
max_y:
cpy #MAX_Y
bcc disp_map
ldy #MAX_Y
disp_map:
stx Map_x
sty Map_y
jsr Display_Map_Show
; waiting for a key to be pressed
kbd_loop:
lda KEYBD
bpl kbd_loop ; bit #8 is set when a character is present (thus A < 0)
sta KEYBD_STROBE
cmp #KEY_UP
beq move_up
cmp #KEY_RIGHT
beq move_right
cmp #KEY_DOWN
beq move_down
cmp #KEY_LEFT
beq move_left
cmp #TAB
beq quit
jmp kbd_loop
move_up:
dec Map_y
jmp disp
move_right:
inc Map_x
jmp disp
move_down:
inc Map_y
jmp disp
move_left:
dec Map_x
jmp disp
quit:
; restore player's view
;sta $C054 ; page 1
sta $C057 ; hires
sta $C053 ; mixed mode on
; restore the 4 last lines of GR1
ldx #39
loop_restore_gr:
lda SAVED_GR_L36, X
sta SRC_GR1_L36, X
lda SAVED_GR_L37, X
sta SRC_GR1_L37, X
lda SAVED_GR_L38, X
sta SRC_GR1_L38, X
lda SAVED_GR_L39, X
sta SRC_GR1_L39, X
dex
bne loop_restore_gr
lda SAVED_GR_L36, X
sta SRC_GR1_L36, X
lda SAVED_GR_L37, X
sta SRC_GR1_L37, X
lda SAVED_GR_L38, X
sta SRC_GR1_L38, X
lda SAVED_GR_L39, X
sta SRC_GR1_L39, X
rts
Display_Map_Init:
; Init coords to view map
lda #0
sta Map_x
sta Map_y
jsr Clear_Gr1
; display GR1
sta $C051 ; full screen
sta $C054 ; page 1
sta $C056 ; lores
sta $C050 ; gfx
sta $C052 ; mixed mode off
rts
.import World
.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 TMP ZERO_9_10
Addr_GR1: ; 3 address blocks to fill GR1 (address -1), stored in reversed endianess.
.word $4F04, $2704, $FF03
; @brief Displays the map in GR1 screen
; @param X top-left x coordinate
; @param Y top-left y coordinate
; X, Y capped by WITH_WOLRD - GR_WIDTH, HEIGHT_WORLD - GR_HEIGHT
; The code in "copy_8x2_lines" copies 16 lines from World
; It is called 3 times to fill the entire screen. Each line
; is two tile heigh.
Display_Map_Show:
; display GR1
sta $C051 ; full screen
sta $C054 ; page 1
sta $C056 ; lores
sta $C050 ; gfx
sta $C052 ; mixed mode off
ld_src:
; compute offset
stx TMP
sty FAC1
lda #WIDTH_WORLD
sta FAC2
jsr mul8
sta SRC_OFFSET+1
txa
clc
adc TMP
sta SRC_OFFSET
lda SRC_OFFSET+1
adc #0
sta SRC_OFFSET+1
; source address in World
lda #<(World-1)
clc
adc SRC_OFFSET
sta SRC_LINE_UP
lda #>(World-1)
adc SRC_OFFSET+1
sta SRC_LINE_UP+1
lda SRC_LINE_UP
clc
adc #WIDTH_WORLD
sta SRC_LINE_DOWN
lda SRC_LINE_UP+1
adc #0
sta SRC_LINE_DOWN+1
ldx #5
stx CPT_FILL
; destination adress in GR1.
lda Addr_GR1,X
sta DST_GR1
dex
lda Addr_GR1,X
sta DST_GR1+1
dex
stx CPT_FILL
fill:
ldx #8
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
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
; update source
lda SRC_LINE_UP
clc
adc #(2*WIDTH_WORLD)
sta SRC_LINE_UP
lda SRC_LINE_UP+1
adc #0
sta SRC_LINE_UP+1
lda SRC_LINE_DOWN
clc
adc #(2*WIDTH_WORLD)
sta SRC_LINE_DOWN
lda SRC_LINE_DOWN+1
adc #0
sta SRC_LINE_DOWN+1
; update destination
clc
lda DST_GR1
adc #$80
sta DST_GR1
lda DST_GR1+1
adc #0
sta DST_GR1+1
dex
bne copy_8x2_lines
; destination adress in GR1.
ldx CPT_FILL
lda Addr_GR1,X
sta DST_GR1
dex
lda Addr_GR1,X
sta DST_GR1+1
dex
stx CPT_FILL
cpx #$FD
bne fill
rts

5
src/display_map.inc Normal file
View File

@ -0,0 +1,5 @@
; inits display of map
.import Display_Map_Init
; @brief Displays the map in GR1 screen
.import Map_Loop

View File

@ -1,24 +1,29 @@
# Configuration for assembler programs which don't need a special setup
# Configuration:
# APPLESOFT required
# 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 = $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 = $C000 - %S;
BSS: file = "", start = __MAIN_LAST__, size = $C000 - __MAIN_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;
RODATA: load = MAIN, type = ro, optional = yes;
DATA: load = MAIN, type = rw, optional = yes, align = $100;
BSS: load = BSS, type = bss, optional = yes, define = yes, align = $100;
# user defined segments
TILES: load = MAIN, type = ro, 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,12 +13,15 @@
; 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 "actors/actors.inc"
.include "world/level.inc"
.include "world/world.inc"
.include "display.inc"
.include "display_map.inc"
.include "memory.inc"
.include "monitor.inc"
.include "common.inc"
.export game_loop
@ -26,70 +29,150 @@
.import set_view_coords
.import view_refresh
; player
.import player_move
.import player_move_inx
.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 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
nop ; Main can jump to a wrong game_loop's addr without this nop :/
; ########### GAME ##########
; @brief Main game loop
game_loop:
ldx Player_XY
ldy Player_XY+1
jsr levels_init
jsr Actors_Init
jsr world_set_player
jsr set_view_coords
jsr view_refresh
level_loop:
jsr level_enter ; Uses NextLevel as level number
; waiting for a key to be pressed
kbd_loop:
lda KEYBD
bpl kbd_loop ; bit #8 is set when a character is present (thus A < 0)
sta KEYBD_STROBE
; *****************
jsr Display_Map_Init
jsr key_action
bvc kbd_loop
ldx Player_XY
ldy Player_XY + 1
jsr world_init
jsr view_init
; *****************
rts
ldx Player_XY
ldy Player_XY+1
jsr world_set_player
jsr set_view_coords
jsr view_refresh
; waiting for a key to be pressed
kbd_loop:
lda KEYBD
bpl kbd_loop ; bit #8 is set when a character is present (thus A < 0)
sta KEYBD_STROBE
jsr key_action
lda ExitLevel
cmp #TRUE
bne kbd_loop
jsr level_exit
jmp level_loop
rts
; 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:
jsr player_move_dey
bvc end_action_move
ldx Player_XY
ldy Player_XY+1
dey
jsr player_move
jmp end_action_move
move_right:
jsr player_move_inx
bvc end_action_move
ldx Player_XY
ldy Player_XY+1
inx
jsr player_move
jmp end_action_move
move_down:
jsr player_move_iny
bvc end_action_move
ldx Player_XY
ldy Player_XY+1
iny
jsr player_move
jmp end_action_move
move_left:
jsr player_move_dex
bvc end_action_move
ldx Player_XY
ldy Player_XY+1
dex
jsr player_move
jmp end_action_move
end_action_move: ; update player/view coordinates and refresh the display
jsr world_set_player
jsr set_view_coords ; coords of the player in XY after player_move_*
jsr view_refresh
jsr view_refresh
rts
display_map:
jsr Map_Loop
rts

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

48
src/io/gr.asm Normal file
View File

@ -0,0 +1,48 @@
; Copyright (C) 2019 Christophe Meneboeuf <christophe@xtof.info>
;
; This program is free software: you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
; the Free Software Foundation, either version 3 of the License, or
; (at your option) any later version.
;
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
; GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public License
; along with this program. If not, see <http://www.gnu.org/licenses/>.
.export Clear_Gr1
.CODE
;@brief Clears GR1 screen
; BEWARE : It will fill the "holes" with 0s
Clear_Gr1:
lda #0 ; black
ldx #0
clear_gr1_1:
sta $400, X
inx
bne clear_gr1_1
ldx #0
clear_gr1_2:
sta $500, X
inx
bne clear_gr1_2
ldx #0
clear_gr1_3:
sta $600, X
inx
bne clear_gr1_3
ldx #0
clear_gr1_4:
sta $700, X
inx
bne clear_gr1_4
rts

1
src/io/gr.inc Normal file
View File

@ -0,0 +1 @@
.import Clear_Gr1

187
src/io/textio.asm Normal file
View File

@ -0,0 +1,187 @@
; Copyright (C) 2019 Christophe Meneboeuf <christophe@xtof.info>
;
; This program is free software: you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
; the Free Software Foundation, either version 3 of the License, or
; (at your option) any later version.
;
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
; GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public License
; along with this program. If not, see <http://www.gnu.org/licenses/>.
.include "../memory.inc"
.export CIN_STR
.export Cin_Str
.export Cin_Char
.export Print
.export ClearTxt
.define SPACE $A0
.define CURSOR $5F
.define RETURN $8D
.define DELETE $FF
.define LEFT $88
.DATA
CIN_STR:
.byte 0
.res 40 ; input string buffer char[40]
.CODE
; brief Clears the 4 line in text zone (mixed mode)
ClearTxt:
ldx #39
lda #SPACE
loop_clear_lines:
sta TXT1_LINE20, X
sta TXT1_LINE21, X
sta TXT1_LINE22, X
sta TXT1_LINE23, X
dex
bpl loop_clear_lines
rts
; brief Scrolls the lines in text zone (mixed mode)
_ScrollTxt:
ldx #39
loop_scroll_lines:
lda TXT1_LINE21, X
sta TXT1_LINE20, X
lda TXT1_LINE22, X
sta TXT1_LINE21, X
lda TXT1_LINE23, X
sta TXT1_LINE22, X
lda #SPACE
sta TXT1_LINE23, X
dex
bpl loop_scroll_lines
rts
.define ADDR_STR ZERO_7_1 ; 2 bytes same as FAC1 and FAC2
; @brief Print the null terminated str
; @param A,X Adress of the string (hi, low)
Print:
stx ADDR_STR
sta ADDR_STR+1
jsr _ScrollTxt
ldy #0
loop_print_str:
lda (ADDR_STR), Y
cmp #0
beq break_print_str
sta TXT1_LINE23, Y
iny
cpy #40
bne loop_print_str
break_print_str:
rts
.macro INC_SEED
clc
lda SEED0
adc #1
sta SEED0
lda SEED1
adc #0
sta SEED1
lda SEED2
adc #0
sta SEED2
lda SEED3
adc #0
sta SEED3
.endmacro
; @brief Gets an input string into the CIN_STR buffer
; @details It will also init the seed
Cin_Str:
jsr _ScrollTxt
; position the cursor
ldx #0
lda #CURSOR
sta TXT1_LINE23, X
; wait for keyboard
cin_str_kbd_loop:
INC_SEED
lda KEYBD
bpl cin_str_kbd_loop ; bit #8 is set when a character is present (thus A < 0)
sta KEYBD_STROBE
cmp #RETURN
beq break_cin ; break if "Return"
cmp #DELETE
beq delete
cmp #LEFT
beq delete
; print key and avance the cursor
sta TXT1_LINE23, X
sta CIN_STR, X
inx
cpx #40 ; eol -> ends anyway
beq break_cin
lda #CURSOR
sta TXT1_LINE23, X
jmp cin_str_kbd_loop
break_cin:
lda #SPACE
sta TXT1_LINE23, X ; erase the cursor
lda #0
sta CIN_STR, X
rts
delete:
cpx #0 ; cannot delete when at pos 0
beq cin_str_kbd_loop
lda #SPACE
sta TXT1_LINE23, X
dex
lda #0
sta CIN_STR, X
lda #CURSOR
sta TXT1_LINE23, X
jmp cin_str_kbd_loop
; @brief Gets an input char
; @detals Entered char in A
Cin_Char:
jsr _ScrollTxt
lda #CURSOR
sta TXT1_LINE23
; wait for keyboard
cin_char_kbd_loop:
lda KEYBD
bpl cin_char_kbd_loop ; bit #8 is set when a character is present (thus A < 0)
sta KEYBD_STROBE
sta TXT1_LINE23
rts

23
src/io/textio.inc Normal file
View File

@ -0,0 +1,23 @@
.import Print
.import ClearTxt
.import Cin_Str
.import Cin_Char
.import CIN_STR
; --- string with high-bit set, null-terminated
; Apple II char < 128 are inverted
.macro ASCIIZ str
.repeat .strlen (str), c
.byte .strat (str, c) | $80
.endrep
.byte 0
.endmacro
.macro PRINT string
lda #>string
ldx #<string
jsr Print
.endmacro

135
src/io/title.asm Normal file
View File

@ -0,0 +1,135 @@
; Copyright (C) 2019 Christophe Meneboeuf <christophe@xtof.info>
;
; This program is free software: you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
; the Free Software Foundation, either version 3 of the License, or
; (at your option) any later version.
;
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
; GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public License
; along with this program. If not, see <http://www.gnu.org/licenses/>.
.include "../monitor.inc"
.include "../memory.inc"
.include "../io/textio.inc"
.include "gr.inc"
.export Title
.DATA
GR_TITLE_00 : .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_01 : .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_02 : .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_03 : .byte $0,$0,$99,$99,$99,$99,$99,$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,$99,$99,$99,$99,$99,$0
GR_TITLE_04 : .byte $0,$0,$99,$99,$99,$99,$99,$0,$0,$88,$88,$88,$88,$0,$0,$88,$88,$88,$88,$0,$0,$0,$88,$88,$0,$0,$0,$88,$88,$88,$88,$88,$0,$0,$99,$99,$99,$99,$99,$0
GR_TITLE_05 : .byte $0,$0,$99,$0,$0,$0,$0,$0,$88,$0,$0,$0,$0,$0,$88,$0,$0,$0,$0,$0,$0,$88,$0,$0,$88,$0,$0,$88,$0,$0,$0,$0,$88,$0,$99,$0,$0,$0,$0,$0
GR_TITLE_06 : .byte $0,$0,$99,$0,$0,$0,$0,$0,$88,$0,$0,$0,$0,$0,$88,$0,$0,$0,$0,$0,$88,$0,$0,$0,$0,$88,$0,$88,$0,$0,$0,$0,$88,$0,$99,$0,$0,$0,$0,$0
GR_TITLE_07 : .byte $0,$0,$99,$99,$99,$0,$0,$0,$88,$88,$88,$88,$0,$0,$88,$0,$0,$0,$0,$0,$88,$0,$0,$0,$0,$88,$0,$88,$88,$88,$88,$88,$0,$0,$99,$99,$99,$0,$0,$0
GR_TITLE_08 : .byte $0,$0,$99,$0,$0,$0,$0,$0,$0,$0,$0,$0,$88,$0,$88,$0,$0,$0,$0,$0,$88,$88,$88,$88,$88,$88,$0,$88,$0,$0,$0,$0,$0,$0,$99,$0,$0,$0,$0,$0
GR_TITLE_09 : .byte $0,$0,$99,$0,$0,$0,$0,$0,$0,$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,$0,$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
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
.CODE
Scroll:
ldx #39
loop_scroll:
lda TXT1_LINE1, X
sta TXT1_LINE0, X
lda TXT1_LINE2, X
sta TXT1_LINE1, X
lda TXT1_LINE3, X
sta TXT1_LINE2, X
lda TXT1_LINE4, X
sta TXT1_LINE3, X
lda TXT1_LINE5, X
sta TXT1_LINE4, X
lda TXT1_LINE6, X
sta TXT1_LINE5, X
lda TXT1_LINE7, X
sta TXT1_LINE6, X
lda TXT1_LINE8, X
sta TXT1_LINE7, X
lda TXT1_LINE9, X
sta TXT1_LINE8, X
lda TXT1_LINE10, X
sta TXT1_LINE9, X
lda TXT1_LINE11, X
sta TXT1_LINE10, X
lda TXT1_LINE12, X
sta TXT1_LINE11, X
lda TXT1_LINE13, X
sta TXT1_LINE12, X
lda TXT1_LINE14, X
sta TXT1_LINE13, X
lda TXT1_LINE15, X
sta TXT1_LINE14, X
lda TXT1_LINE16, X
sta TXT1_LINE15, X
lda TXT1_LINE17, X
sta TXT1_LINE16, X
lda TXT1_LINE18, X
sta TXT1_LINE17, X
lda TXT1_LINE19, X
sta TXT1_LINE18, X
dex
bpl loop_scroll
rts
.DATA
Title_Scr_Addr:
.word GR_TITLE_01, GR_TITLE_02, GR_TITLE_03, GR_TITLE_04, GR_TITLE_05, GR_TITLE_06, GR_TITLE_07, GR_TITLE_08, GR_TITLE_09, GR_TITLE_10
.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 and main game menu
Title:
; Title Screen
jsr Clear_Gr1
jsr ClearTxt
sta $C054 ; page 1
sta $C056 ; lores
sta $C050 ; gfx
sta $C053 ; mixed mode on
ldy #$FE
loop_scrolling:
lda #$A2 ; wait for 66ms
jsr WAIT
ldx #39
loop_lines:
lda GR_TITLE_00, X
sta TXT1_LINE19, X
dex
bpl loop_lines
jsr Scroll
iny
iny
lda Title_Scr_Addr, Y
sta loop_lines+1
lda Title_Scr_Addr+1, Y
sta loop_lines+2
cpy #$26
bne loop_scrolling
rts

View File

@ -17,33 +17,158 @@
.include "random.inc"
.include "memory.inc"
.include "monitor.inc"
.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 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__
.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:
; init the seed of rnd
lda #$DE
sta SEED0
lda #$AD
sta SEED1
lda #$BE
sta SEED2
lda #$EF
sta SEED3
jsr player_init
jsr world_init
jsr view_init
jsr game_loop
; jsr meminit // Uncomment to zero memory, for debug
; Relocations after the HGR "hole"
; relocating code
lda #<__CODE2_LOAD__
sta FROM
lda #>__CODE2_LOAD__
sta FROM+1
lda #<__CODE2_RUN__
sta TO
lda #>__CODE2_RUN__
sta TO+1
lda #<__CODE2_SIZE__
sta SIZEL
lda #>__CODE2_SIZE__
sta SIZEH
jsr memcpy
; relocating RODATA
lda #<__RODATA_LOAD__
sta FROM
lda #>__RODATA_LOAD__
sta FROM+1
lda #<__RODATA_RUN__
sta TO
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
lda #>__DATA_SIZE__
sta SIZEH
jsr memcpy
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
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

@ -5,6 +5,7 @@
.define FAC2 ZERO_7_2
.export mul8
.export Modulus
.CODE
@ -19,13 +20,90 @@ mul8:
lda #$00
ldx #$08
clc
clc
m0: bcc m1
clc
clc
adc FAC2
m1: ror
m1: ror
ror FAC1
dex
dex
bpl m0
ldx FAC1
rts
rts
; 8 bit division
; Inputs:
; FAC1 = 8-bit numerator
; FAC2 = 8-bit denominator
; Outputs:
; FAC1 = 8-bit quotient of TQ / B
; A = remainder of TQ / B
; source: http://6502org.wikidot.com/software-math-intdiv
; div8:
; lda #0
; ldx #8
; asl FAC1
; lbl_1:
; rol A
; cmp FAC2
; bcc lbl_2
; sbc FAC2
; lbl_2:
; rol FAC1
; dex
; bne lbl_1
; rts
; source: https://www.codebase64.org/doku.php?id=base:8bit_divide_8bit_product
; 8bit/8bit division
; by White Flame
;
; Input: num, denom in zeropage
; Output: num = quotient, .A = remainder
; div8:
; lda #$00
; ldx #$07
; clc
; : rol FAC1
; rol
; cmp FAC2
; bcc :+
; sbc FAC2
; : dex
; bpl :--
; rol FAC1
; 19 bytes
;
; Best case = 154 cycles
; Worst case = 170 cycles
;
; With immediate denom:
; Best case = 146 cycles
; Worst case = 162 cycles
;
; Unrolled with variable denom:
; Best case = 106 cycles
; Worst case = 127 cycles
;
; Unrolled with immediate denom:
; Best case = 98 cycles
; Worst case = 111 cycles
; Returns A % X in A
; Source: http://forum.6502.org/viewtopic.php?t=130
Modulus:
sec
stx FAC2
lbl_modulus:
sbc FAC2
bcs lbl_modulus
adc FAC2
rts

View File

@ -13,11 +13,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/>.
.define FAC1 ZERO_7_1
.define FAC2 ZERO_7_2
.import mul8
.import Modulus
.import div8
; Inverts a positive number to its 2's complement counterpart
; The bits are all reversed then one is added
@ -28,3 +30,26 @@
clc
adc #$01
.endmacro
.macro ADD16 addr, csteL, csteH
clc
lda addr
adc csteL
sta addr
lda addr+1
adc csteH
sta addr+1
.endmacro
.macro DEC16 addr, cste
sec
lda addr
sbc cste
sta addr
lda addr+1
sbc #0
sta addr+1
.endmacro

138
src/memory.asm Normal file
View File

@ -0,0 +1,138 @@
; Copyright (C) 2019 Christophe Meneboeuf <christophe@xtof.info>
;
; This program is free software: you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
; the Free Software Foundation, either version 3 of the License, or
; (at your option) any later version.
;
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
; GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public License
; along with this program. If not, see <http://www.gnu.org/licenses/>.
.include "memory.inc"
.export memcpy
.export memset
.export meminit
.CODE
; http://www.6502.org/source/general/memory_move.html
; Move memory up
;
; FROM = source start address
; TO = destination start address
; SIZE = number of bytes to move
;
memcpy: LDX SIZEH ; the last byte must be moved first
CLC ; start at the final pages of FROM and TO
TXA
ADC FROM+1
STA FROM+1
CLC
TXA
ADC TO+1
STA TO+1
INX ; allows the use of BNE after the DEX below
LDY SIZEL
BEQ MU3
DEY ; move bytes on the last page first
BEQ MU2
MU1: LDA (FROM),Y
STA (TO),Y
DEY
BNE MU1
MU2: LDA (FROM),Y ; handle Y = 0 separately
STA (TO),Y
MU3: DEY
DEC FROM+1 ; move the next page (if any)
DEC TO+1
DEX
BNE MU1
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

@ -1,5 +1,5 @@
; Copyright (C) 2018 Christophe Meneboeuf <christophe@xtof.info>
; Copyright (C) 2019 Christophe Meneboeuf <christophe@xtof.info>
;
; This program is free software: you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
@ -19,7 +19,11 @@
; Free locations in Zero Page: not used by either
; the Monitor, Applesoft, Integer Basic, DOS3.3 or PRODOS
; reserved locations
.define RESERVED01 $52
; locations for the random generator
; little endian
.define SEED0 $6
.define SEED1 $7
.define SEED2 $8
@ -53,11 +57,76 @@
.define ZERO_7_2 $CF
.define ZERO_8_1 $D6
.define ZERO_8_2 $D7
.define ZERO_8_2 $D7
.define ZERO_9_1 $F0
.define ZERO_9_2 $F1
.define ZERO_9_3 $F2
.define ZERO_9_4 $F3
.define ZERO_9_5 $F4
.define ZERO_9_6 $F5
.define ZERO_9_7 $F6
.define ZERO_9_8 $F7
.define ZERO_9_9 $F8
.define ZERO_9_10 $F9
; ************ I/O ************
.define KEYBD $C000
.define KEYBD_STROBE $C010
; *********** HIRES ************
.define ADDR_HGR1 $2000
.define ADDR_HGR1 $2000
.define ADDR_HGR2 $4000
; ********** TEXT *************
.define TXT1_LINE0 $400
.define TXT1_LINE1 $480
.define TXT1_LINE2 $500
.define TXT1_LINE3 $580
.define TXT1_LINE4 $600
.define TXT1_LINE5 $680
.define TXT1_LINE6 $700
.define TXT1_LINE7 $780
.define TXT1_LINE8 $428
.define TXT1_LINE9 $4A8
.define TXT1_LINE10 $528
.define TXT1_LINE11 $5A8
.define TXT1_LINE12 $628
.define TXT1_LINE13 $6A8
.define TXT1_LINE14 $728
.define TXT1_LINE15 $7A8
.define TXT1_LINE16 $450
.define TXT1_LINE17 $4D0
.define TXT1_LINE18 $550
.define TXT1_LINE19 $5D0
.define TXT1_LINE20 $650
.define TXT1_LINE21 $6D0
.define TXT1_LINE22 $750
.define TXT1_LINE23 $7D0
.import TXT1_LINES
; *********** CUSTOM ROUTINES *********
.define FROM ZERO_2_1 ; 2 bytes
.define TO ZERO_2_3 ; 2 bytes
.define SIZEH ZERO_8_2
.define SIZEL ZERO_8_1
; ************ MACROS ***********
; pushes addr to the stack
; A is detroyed
.macro PUSH addr
lda addr
pha
.endmacro
; pops addr from the stack
; A is detroyed
.macro POP addr
pla
sta addr
.endmacro

View File

@ -50,6 +50,7 @@
.define VTAB $fc22 ; Vertical tab
.define VTABZ $fc24 ; Vertical tab (alternate entry)
.define HOME $fc58 ; Home cursor and clear to end of page
.define WAIT $fca8 ; wait : read "Assembly Cookbook for the Apple II/IIe"
.define RDKEY $fd0c ; Get an input character
.define CROUT $fd8e ; Issue a carriage return
.define PRBYTE $fdda ; Print a hexadecimal byte

View File

@ -14,156 +14,107 @@
; 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 "common.inc"
.include "memory.inc"
.include "monitor.inc"
.include "io/textio.inc"
.include "world/world.inc"
.include "actors/actors.inc"
; init the player's structures
.export player_init
; exectutes the tile's reaction and updates the player's position if possible
; Destroys ZEROS_2_1 -> 2_5
.export player_move
; All the following functions returns the new player position:
; x in X and y in Y
; 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 Compute_Maze_Addr
.import Reactions_lsb
.import Reactions_msb
.import ActorTypes
.import ActorPositions
.BSS
Player_XY: .res 2
.define TO_BE_PATCHED 0
.define Player_XY ActorPositions + eACTORTYPES::PLAYER
.DATA
STR_HIT_WALL: ASCIIZ "YOU HIT A WALL"
.CODE
; Player starts at [1:1]
; @brief Player initial coords
; @param X player's x
; @param Y player's y
player_init:
ldx #1
stx Player_XY
stx Player_XY+1
sty Player_XY+1
rts
; @param X target tile's x
; @param Y target tile's y
; @return TRUE in A if the player can move to the tile, FALE otherwise
.define ADDR_IN_MAZE ZERO_2_1 ; 2 bytes
.define NEW_PLAYER_XY ZERO_2_4 ; 2 bytes
player_move:
; !!! 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) !!!
stx NEW_PLAYER_XY
sty NEW_PLAYER_XY+1
.define ADDR_IN_MAZE ZERO_2_1
player_move_inx:
jsr Compute_Maze_Addr
; check if moving is possible
ldx Player_XY
; test for border
cpx #WIDTH_MAZE - 1 ; last tile is always a wall...
beq return_from_player_move
; test that x+1 is "WALKABLE"
ldy Player_XY+1
jsr compute_maze_addr ; we get the adress for x,y then we increment x
; get the actor id
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 return_from_player_move ; carry cleared if A is strictly the lesser --> not walkable
ldy #0
lda (ADDR_IN_MAZE), Y
tax
; get the actor's type
lda ActorTypes, X
tay
; get the reaction address
lda Reactions_lsb, Y
sta FUNC_REACTION + 1
lda Reactions_msb, Y
sta FUNC_REACTION+2
FUNC_REACTION : jsr TO_BE_PATCHED ; actord id in Y
cmp #TRUE
bne end_player_move
ldx NEW_PLAYER_XY
stx Player_XY
ldy NEW_PLAYER_XY+1
sty Player_XY+1
end_player_move:
ldx Player_XY
inx
stx Player_XY ; walkable
bvc return_from_player_move
player_move_dex:
; check if moving is possible
ldx Player_XY
; test for border
cpx #1 ; 1st tile is always a wall...
beq return_from_player_move
; test that x+1 is "WALKABLE"
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 return_from_player_move ; carry cleared if A is strictly the lesser --> not walkable
ldx Player_XY
dex
stx Player_XY ; walkable
bvc return_from_player_move
rts
; Common code to return from the moves.
; Moves BRANCH to here
return_from_player_move:
; return player's coordinates
ldx Player_XY
ldy Player_XY+1
rts
hit_wall:
PRINT STR_HIT_WALL
jmp return_from_player_move
player_move_iny:
; check if moving is possible
ldy Player_XY+1
; test for border
cpy #HEIGHT_MAZE - 1 ; last tile is always a wall...
beq return_from_player_move
; test that y+1 is "WALKABLE"
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 return_from_player_move ; carry cleared if A is strictly the lesser --> not walkable
ldy Player_XY+1 ; walkable
iny
sty Player_XY+1
bvc return_from_player_move
player_move_dey:
; check if moving is possible
ldy Player_XY+1
; test for border
cpy #1 ; 1st tile is always a wall...
beq return_from_player_move
; test that y-1 is "WALKABLE"
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 return_from_player_move ; carry cleared if A is strictly the lesser --> not walkable
ldy Player_XY+1 ; walkable
dey
sty Player_XY+1
bvc return_from_player_move
.undef ADDR_IN_MAZE

View File

@ -3,63 +3,26 @@
.include "memory.inc"
.export random8
.export Random8
.export Random8_Init
.export Random8_RestoreRandomness
.export Random8_SaveRandomness
.export DBG_SEED
.define TMP ZERO_2_1 ; requires 4 bytes
.define MOD ZERO_2_5
.define TMP RESERVED01
.BSS
.align 256
T0: .res 256
T1: .res 256
T2: .res 256
T3: .res 256
T0COPY: .res 256
.CODE
;.align 256
; Linear congruential pseudo-random number generator
;
; Get the next SEED and obtain an 8-bit random number from it
;
; Requires the RAND subroutine
;
; Enter with:
;
; accumulator = modulus
;
; Exit with:
;
; accumulator = random number, 0 <= accumulator < modulus
;
; MOD, TMP, TMP+1, and TMP+2 are overwritten
;
; Note that TMP to TMP+2 are only used after RAND is called.
;
random8: STA MOD ; store modulus in MOD
JSR RAND ; get next seed
LDA #0 ; multiply SEED by MOD
STA TMP+2
STA TMP+1
STA TMP
SEC
ROR MOD ; shift out modulus, shifting in a 1 (will loop 8 times)
R8A: BCC R8B ; branch if a zero was shifted out
CLC ; add SEED, keep upper 8 bits of product in accumulator
TAX
LDA TMP
ADC SEED0
STA TMP
LDA TMP+1
ADC SEED1
STA TMP+1
LDA TMP+2
ADC SEED2
STA TMP+2
TXA
ADC SEED3
R8B: ROR ; shift product right
ROR TMP+2
ROR TMP+1
ROR TMP
LSR MOD ; loop until all 8 bits of MOD have been shifted out
BNE R8A
RTS
DBG_SEED: .byte 0,0,0,0 ; MUST NOT BE RELOCATED!
; Linear congruential pseudo-random number generator
;
@ -79,79 +42,116 @@ R8B: ROR ; shift product right
; SEED2 = byte 2 of seed
; SEED3 = byte 3 of seed
;
; TMP, TMP+1, TMP+2 and TMP+3 are overwritten
; TMP is overwritten
;
; Assuming that (a) SEED0 to SEED3 and TMP+0 to TMP+3 are all located on page
; zero, and (b) none of the branches cross a page boundary:
; For maximum speed, locate each table on a page boundary
;
; Space: 106 bytes
; Speed: JSR RAND takes 517 cycles
; Assuming that (a) SEED0 to SEED3 and TMP are located on page zero, and (b)
; all four tables start on a page boundary:
;
RAND: CLC ; copy SEED into TMP
LDA SEED0 ; and compute SEED = SEED * $10000 + SEED + 1
STA TMP
; Space: 58 bytes for the routine
; 1024 bytes for the tables
; Speed: JSR RAND takes 94 cycles
;
Random8:
CLC ; compute lower 32 bits of:
LDX SEED0 ; 1664525 * ($100 * SEED1 + SEED0) + 1
LDY SEED1
LDA T0,X
ADC #1
STA SEED0
LDA SEED1
STA TMP+1
ADC #0
LDA T1,X
ADC T0,Y
STA SEED1
LDA SEED2
STA TMP+2
ADC TMP
LDA T2,X
ADC T1,Y
STA TMP
LDA T3,X
ADC T2,Y
TAY ; keep byte 3 in Y for now (for speed)
CLC ; add lower 32 bits of:
LDX SEED2 ; 1664525 * ($10000 * SEED2)
LDA TMP
ADC T0,X
STA SEED2
LDA SEED3
STA TMP+3
ADC TMP+1
TYA
ADC T1,X
CLC
LDX SEED3 ; add lower 32 bits of:
ADC T0,X ; 1664525 * ($1000000 * SEED3)
STA SEED3
;
; Bit 7 of $00, $19, $66, and $0D is 0, so only 6 shifts are necessary
;
LDY #5
RAND1: ASL TMP ; shift TMP (old seed) left
ROL TMP+1
ROL TMP+2
ROL TMP+3
;
; Get X from the RAND4 table. When:
;
; X = $00, SEED = SEED + $10000 * TMP
; X = $01, SEED = SEED + $100 * TMP
; X = $FE, SEED = SEED + $10000 * TMP + TMP
; X = $FF, SEED = SEED + $100 * TMP + TMP
;
LDX RAND4,Y
BPL RAND2 ; branch if X = $00 or X = $01
CLC ; SEED = SEED + TMP
LDA SEED0
ADC TMP
STA SEED0
LDA SEED1
ADC TMP+1
STA SEED1
LDA SEED2
ADC TMP+2
STA SEED2
LDA SEED3
ADC TMP+3
STA SEED3
INX ; $FE -> $00, $FF -> $01
INX
RAND2: CLC
BEQ RAND3 ; if X = $00, SEED = SEED + TMP * $10000
LDA SEED1 ; SEED = SEED + TMP * $100
ADC TMP
STA SEED1
RAND3: LDA SEED2
ADC TMP,X
STA SEED2
LDA SEED3
ADC TMP+1,X
STA SEED3
DEY
BPL RAND1
RTS
RAND4: .byte $01,$01,$00,$FE,$FF,$01
;
; Generate T0, T1, T2 and T3 tables
;
; A different multiplier can be used by simply replacing the four bytes
; that are commented below
;
; To speed this routine up (which will make the routine one byte longer):
; 1. Delete the first INX instruction
; 2. Replace LDA Tn-1,X with LDA Tn,X (n = 0 to 3)
; 3. Replace STA Tn,X with STA Tn+1,X (n = 0 to 3)
; 4. Insert CPX #$FF between the INX and BNE GT1
;
Random8_Init:
; Xtof's dbg Saving the seed
lda SEED0
sta DBG_SEED
lda SEED1
sta DBG_SEED+1
lda SEED2
sta DBG_SEED+2
lda SEED3
sta DBG_SEED+3
; Xtof's dbg
LDX #0 ; 1664525 * 0 = 0
STX T0
STX T1
STX T2
STX T3
INX
CLC
GT1: LDA T0-1,X ; add 1664525 to previous entry to get next entry
ADC #$0D ; byte 0 of multiplier
STA T0,X
LDA T1-1,X
ADC #$66 ; byte 1 of multiplier
STA T1,X
LDA T2-1,X
ADC #$19 ; byte 2 of multiplier
STA T2,X
LDA T3-1,X
ADC #$00 ; byte 3 of multiplier
STA T3,X
INX ; note: carry will be clear here
BNE GT1
RTS
Random8_RestoreRandomness:
ldx #$FF
restore_loop:
lda T0COPY, X
sta T0, X
dex
bne restore_loop
lda T0COPY, X
sta T0, X
rts
Random8_SaveRandomness:
ldx #$FF
save_loop:
lda T0, X
sta T0COPY, X
dex
bne save_loop
lda T0, X
sta T0COPY, X
rts

View File

@ -1,7 +1,10 @@
; Enter with:
; accumulator = modulus
;
; Exit with:
; accumulator = random number, 0 <= accumulator < modulus
.import random8
; A = random number
.import Random8
.import Random8_Init
.import Random8_RestoreRandomness
.import Random8_SaveRandomness

View File

@ -16,7 +16,7 @@
.export TILES
.SEGMENT "TILES"
.SEGMENT "RODATA"
.ALIGN 256
PLAYER:
@ -36,7 +36,7 @@ PLAYER:
.byte 16, 16, 66, 0
.byte 16, 16, 66, 0
.byte 16, 20, 74, 0
FLOOR_BLACK:
FLOOR_1:
.byte $00, $00, $00, $00
.byte $00, $00, $00, $00
.byte $00, $00, $00, $00
@ -53,7 +53,7 @@ FLOOR_BLACK:
.byte $00, $00, $00, $00
.byte $00, $00, $00, $00
.byte $00, $00, $00, $00
FLOOR_ORANGE:
FLOOR_2:
.byte 85, 42, 85, 42
.byte 1, 32, 0, 0
.byte 1, 32, 0, 0
@ -70,7 +70,7 @@ FLOOR_ORANGE:
.byte 16, 0, 64, 0
.byte 16, 0, 64, 0
.byte 16, 0, 64, 0
FLOOR_VIOLET:
FLOOR_3:
.byte $55, $2A, $55, $2A
.byte $55, $2A, $55, $2A
.byte $55, $2A, $55, $2A
@ -87,7 +87,7 @@ FLOOR_VIOLET:
.byte $55, $2A, $55, $2A
.byte $55, $2A, $55, $2A
.byte $55, $2A, $55, $2A
FLOOR_BLUE:
FLOOR_4:
.byte $D5, $AA, $D5, $AA
.byte $D5, $AA, $D5, $AA
.byte $D5, $AA, $D5, $AA
@ -104,24 +104,41 @@ FLOOR_BLUE:
.byte $D5, $AA, $D5, $AA
.byte $D5, $AA, $D5, $AA
.byte $D5, $AA, $D5, $AA
STAIR_DOWN:
.byte $55, $2A, $55, $2A
.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
.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 $71, $79, $3C, $1E
.byte $71, $7F, $7F, $1F
.byte $01, $8A, $95, $A8
STAIR_UP:
.byte $55, $2A, $55, $2A
.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 $7F, $7F, $7F, $7F
.byte $7F, $7F, $7F, $7F
.byte $7F, $7F, $7F, $7F
.byte $7F, $7F, $7F, $7F
.byte $7F, $7F, $7F, $7F
.byte $7F, $7F, $7F, $7F
.byte $7F, $7F, $7F, $7F
.byte $7F, $7F, $7F, $7F
.byte $7F, $7F, $7F, $7F
.byte $7F, $7F, $7F, $7F
.byte $7F, $7F, $7F, $7F
.byte $7F, $7F, $7F, $7F
.byte $7F, $7F, $7F, $7F
.byte $7F, $7F, $7F, $7F
.byte $7F, $7F, $7F, $7F
.byte $7F, $7F, $7F, $7F
WALL_2:
.byte 197, 138, 213, 168
.byte 197, 138, 213, 168
.byte 197, 138, 213, 168
@ -138,6 +155,91 @@ WALL_2:
.byte 209, 130, 213, 168
.byte 209, 138, 212, 168
.byte 0, 0, 0, 0
WALL_2:
.byte $7F, $7F, $7F, $7F
.byte $7F, $7F, $7F, $7F
.byte $7F, $7F, $7F, $7F
.byte $7F, $7F, $7F, $7F
.byte $7F, $7F, $7F, $7F
.byte $7F, $7F, $7F, $7F
.byte $7F, $7F, $7F, $7F
.byte $7F, $7F, $7F, $7F
.byte $7F, $7F, $7F, $7F
.byte $7F, $7F, $7F, $7F
.byte $7F, $7F, $7F, $7F
.byte $7F, $7F, $7F, $7F
.byte $7F, $7F, $7F, $7F
.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
@ -157,9 +259,35 @@ UNKNOWN:
.byte $80, $80, $80, $80
.SEGMENT "DATA"
.ALIGN 256
; DON"T FORGET TO UPDATE NB_TILES!!
; Tiles used by ACTORS
; 128 addresses
TILES:
.word PLAYER, FLOOR_BLACK, FLOOR_ORANGE, FLOOR_VIOLET, FLOOR_BLUE, WALL_1, WALL_2, UNKNOWN
.word PLAYER
; 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

@ -18,7 +18,6 @@
.import TILES
.define NB_TILES 8

View File

@ -1,195 +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
world_init:
; Saving the first tile on which the player stands
; FIXME player could be standing anywhere on any type of floor
ldx #1
ldy #1
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
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 X
rts
.DATA
.align 256
World:; .res (WIDTH_WORLD) * (HEIGHT_WORLD)
.byte 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06
.byte 06, 02, 02, 06, 06, 06, 06, 06, 06, 06, 02, 02, 02, 02, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 06, 06, 06, 02, 02, 02, 02, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06
.byte 06, 02, 02, 02, 02, 02, 02, 06, 06, 06, 02, 02, 02, 02, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 02, 02, 02, 02, 02, 02, 06, 06, 06, 06, 06, 02, 02, 02, 06, 06, 02, 02, 02, 02, 02, 02, 02, 06, 06, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 06, 06
.byte 06, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 06, 06, 02, 02, 02, 02, 02, 02, 06, 06, 02, 02, 02, 02, 02, 02, 06, 06, 06, 06, 06, 02, 02, 02, 06, 06, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 06, 06, 06, 02, 02, 02, 02, 02, 06, 06
.byte 06, 02, 02, 02, 02, 02, 02, 06, 06, 02, 02, 02, 02, 02, 02, 06, 06, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 06, 06, 02, 02, 02, 02, 02, 02, 06, 06, 06, 02, 02, 02, 02, 06, 06, 06, 02, 02, 02, 02, 02, 06, 06
.byte 06, 02, 02, 02, 02, 02, 02, 06, 06, 06, 02, 02, 02, 02, 02, 06, 06, 02, 02, 02, 02, 02, 02, 06, 06, 02, 02, 02, 02, 02, 02, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 02, 02, 02, 02, 02, 02, 06, 06, 06, 02, 02, 02, 02, 06, 06, 06, 06, 06, 06, 02, 06, 06, 06
.byte 06, 02, 02, 02, 02, 02, 02, 06, 06, 06, 02, 02, 02, 02, 02, 06, 06, 02, 02, 02, 02, 02, 02, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 02, 02, 02, 02, 02, 02, 06, 06, 06, 02, 02, 02, 02, 06, 06, 06, 06, 06, 02, 02, 06, 06, 06
.byte 06, 06, 06, 06, 02, 06, 06, 06, 06, 06, 06, 06, 06, 06, 02, 06, 06, 06, 06, 06, 02, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 02, 06, 06, 06, 06
.byte 06, 06, 06, 02, 02, 06, 06, 06, 06, 06, 06, 06, 06, 06, 02, 06, 06, 06, 06, 06, 02, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 02, 02, 02, 06, 06, 06, 06
.byte 06, 06, 06, 02, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 02, 06, 06, 02, 02, 02, 02, 02, 06, 06, 06, 02, 02, 02, 02, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 02, 02, 02, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 02, 02, 02, 02, 06, 06, 06
.byte 06, 06, 02, 02, 02, 02, 02, 06, 06, 06, 06, 06, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 06, 06, 06, 02, 02, 02, 02, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 02, 02, 02, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 02, 02, 02, 02, 02, 02, 06, 06, 06
.byte 06, 06, 02, 02, 02, 02, 02, 06, 06, 06, 06, 06, 02, 02, 02, 06, 06, 02, 02, 02, 02, 02, 06, 06, 06, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 06, 02, 02, 02, 02, 06, 06, 06, 06, 06, 06, 06, 06, 02, 02, 02, 02, 06, 02, 02, 02, 02, 06, 06, 06
.byte 06, 06, 02, 02, 02, 02, 02, 06, 06, 06, 06, 06, 02, 02, 02, 06, 06, 02, 02, 02, 02, 02, 06, 06, 06, 06, 06, 02, 06, 06, 06, 06, 06, 06, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 06, 06, 06, 06, 06, 06, 06, 06, 02, 02, 02, 06, 06, 02, 02, 02, 02, 06, 06, 06
.byte 06, 06, 02, 02, 02, 02, 02, 06, 06, 06, 06, 06, 02, 02, 02, 06, 06, 02, 02, 02, 02, 02, 06, 06, 06, 06, 06, 02, 06, 06, 06, 06, 06, 06, 02, 02, 02, 02, 02, 06, 06, 06, 06, 02, 06, 06, 06, 06, 06, 06, 06, 06, 02, 02, 02, 06, 06, 02, 02, 02, 02, 06, 06, 06
.byte 06, 06, 02, 02, 02, 02, 02, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 02, 06, 06, 06, 06, 06, 06, 02, 02, 02, 02, 02, 06, 06, 06, 06, 02, 06, 06, 06, 06, 06, 06, 06, 06, 02, 02, 02, 06, 06, 02, 02, 02, 02, 06, 06, 06
.byte 06, 06, 06, 06, 06, 06, 02, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 02, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 02, 06, 06, 06, 06, 06, 06, 02, 02, 02, 06, 06, 06, 06, 06, 06, 02, 06, 06, 06, 06
.byte 06, 06, 06, 06, 06, 06, 02, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 02, 02, 02, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 02, 06, 06, 06, 06, 06, 06, 02, 06, 06, 06, 06, 06, 06, 06, 06, 02, 06, 06, 06, 06
.byte 06, 06, 06, 06, 02, 02, 02, 06, 06, 06, 02, 02, 02, 02, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 02, 02, 02, 02, 02, 02, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 02, 02, 02, 02, 06, 06, 06, 06, 06, 02, 06, 06, 06, 06, 06, 06, 06, 02, 02, 02, 02, 06, 06
.byte 06, 06, 06, 06, 02, 02, 02, 06, 06, 06, 02, 02, 02, 02, 06, 06, 06, 06, 02, 02, 02, 02, 02, 06, 06, 02, 02, 02, 02, 02, 02, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 02, 02, 02, 02, 06, 06, 06, 06, 02, 02, 02, 02, 02, 02, 06, 06, 06, 02, 02, 02, 02, 06, 06
.byte 06, 06, 06, 06, 02, 02, 02, 06, 06, 02, 02, 02, 02, 02, 06, 06, 06, 06, 02, 02, 02, 02, 02, 06, 06, 02, 02, 02, 02, 02, 02, 06, 06, 02, 02, 02, 02, 02, 02, 06, 06, 02, 02, 02, 02, 06, 06, 06, 06, 02, 02, 02, 02, 02, 02, 06, 06, 06, 02, 02, 02, 02, 06, 06
.byte 06, 06, 06, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 06, 06, 06, 06, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 06, 06, 02, 02, 02, 02, 02, 02, 06, 06, 02, 02, 02, 02, 06, 06, 06, 06, 02, 02, 02, 02, 02, 02, 06, 06, 06, 02, 02, 02, 02, 06, 06
.byte 06, 06, 06, 02, 02, 02, 02, 06, 06, 06, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 06, 06, 02, 02, 02, 02, 02, 02, 06, 06, 02, 02, 02, 02, 02, 02, 06, 06, 02, 02, 02, 02, 06, 06, 06, 06, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 06, 06
.byte 06, 06, 06, 02, 06, 06, 06, 06, 06, 06, 02, 02, 02, 02, 06, 06, 06, 06, 02, 02, 02, 02, 02, 06, 06, 02, 02, 02, 02, 02, 02, 06, 06, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 02, 02, 02, 02, 06, 06
.byte 06, 06, 06, 02, 06, 06, 06, 06, 06, 06, 06, 06, 06, 02, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 02, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 02, 06, 06, 06, 06
.byte 06, 06, 06, 02, 06, 06, 06, 06, 06, 06, 06, 06, 06, 02, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 02, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 02, 06, 06, 06, 06
.byte 06, 06, 06, 02, 06, 06, 06, 06, 06, 06, 02, 02, 02, 02, 02, 06, 06, 06, 02, 02, 02, 02, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 02, 02, 02, 02, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 02, 06, 06, 06, 06
.byte 06, 06, 06, 02, 06, 06, 06, 06, 06, 06, 02, 02, 02, 02, 02, 06, 06, 06, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 06, 06, 06, 06, 02, 02, 02, 02, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 02, 02, 02, 02, 06
.byte 06, 02, 02, 02, 02, 06, 06, 06, 06, 06, 02, 02, 02, 02, 02, 06, 06, 02, 02, 02, 02, 02, 06, 06, 02, 02, 02, 02, 02, 02, 02, 06, 06, 06, 06, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 06, 06, 06, 02, 02, 02, 02, 06, 06, 06, 06, 06, 06, 02, 02, 02, 06
.byte 06, 02, 02, 02, 02, 06, 06, 06, 06, 06, 02, 02, 02, 02, 02, 06, 06, 02, 02, 02, 02, 02, 06, 06, 02, 02, 02, 02, 02, 02, 02, 06, 06, 06, 06, 02, 02, 02, 02, 06, 06, 06, 02, 02, 02, 02, 02, 06, 06, 06, 02, 02, 02, 02, 06, 06, 06, 06, 06, 06, 02, 02, 02, 06
.byte 06, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 06, 06, 02, 06, 06, 06, 06, 06, 06, 02, 02, 02, 02, 02, 02, 02, 06, 06, 06, 06, 02, 02, 02, 02, 06, 06, 06, 02, 02, 02, 02, 02, 06, 06, 06, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 06
.byte 06, 06, 02, 06, 06, 06, 06, 06, 06, 06, 02, 02, 02, 02, 02, 06, 06, 02, 06, 06, 06, 06, 06, 06, 02, 02, 02, 02, 02, 02, 02, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 02, 02, 02, 02, 06, 06, 06, 06, 06, 06, 02, 02, 02, 06
.byte 06, 06, 02, 02, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 02, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 02, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 02, 06, 06, 06, 06, 06, 06, 06, 06, 06, 02, 06, 06
.byte 06, 06, 06, 02, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 02, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 02, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 02, 06, 06, 06, 06, 06, 06, 06, 06, 06, 02, 02, 06
.byte 06, 06, 02, 02, 02, 02, 02, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 02, 02, 02, 02, 02, 02, 06, 06, 06, 06, 06, 02, 06, 06, 06, 06, 06, 02, 02, 02, 02, 02, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 02, 02, 02, 06, 06, 06, 06, 06, 06, 06, 02, 02, 02, 06
.byte 06, 06, 02, 02, 02, 02, 02, 06, 06, 06, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 06, 06, 02, 02, 02, 02, 06, 06, 06, 06, 06, 02, 02, 02, 02, 02, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 02, 02, 02, 06, 06, 06, 06, 06, 06, 06, 02, 02, 02, 06
.byte 06, 06, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 06, 02, 02, 02, 02, 02, 02, 06, 06, 02, 02, 02, 02, 06, 06, 06, 06, 06, 02, 02, 02, 02, 02, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 02, 02, 02, 06, 06, 06, 06, 06, 06, 06, 02, 02, 02, 06
.byte 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 02, 02, 02, 02, 02, 06, 06, 02, 02, 02, 02, 02, 02, 06, 06, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 06, 06, 06, 02, 02, 02, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06
.byte 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 02, 02, 02, 02, 02, 06, 06, 02, 02, 02, 02, 02, 02, 06, 06, 02, 02, 02, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 02, 06, 06, 06, 06, 06, 06, 06
.byte 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 02, 02, 02, 02, 02, 02, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 02, 02, 02, 02, 02, 02, 06, 06, 06, 02, 02, 02, 06, 06, 06
.byte 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06, 06

View File

@ -1,33 +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 WIDTH_MAZE 64
.define HEIGHT_MAZE 40
.define SIZE_BORDER 0
.define WIDTH_WORLD WIDTH_MAZE + 2*SIZE_BORDER
.define HEIGHT_WORLD HEIGHT_MAZE + 2*SIZE_BORDER
.enum ACTORS
PLAYER = 0
FLOOR_BLACK = 1
FLOOR_ORANGE
FLOOR_VIOLET
FLOOR_BLUE
WALKABLE = FLOOR_BLUE ; 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

228
src/world/level.asm Normal file
View File

@ -0,0 +1,228 @@
; 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/>.
.include "../common.inc"
.include "../memory.inc"
.include "../random.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 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
LevelIsBuilt: .res 1
LevelConfigs: .res 1 + NB_LEVELS * SIZEOF_CONF_LEVEL
.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:
; 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
; global vars
lda #0
sta CurrentLevel
sta NextLevel
lda #FALSE
sta ExitLevel
rts
; @param: Uses NextLevel as level number
.define LEVEL_STATE_OFFSET ZERO_9_1
.define ADDR_LEVEL_CONF ZERO_9_2 ; 2 bytes
level_enter:
lda NextLevel
jsr LoadState
lda LevelIsBuilt
cmp #TRUE
beq level_was_built
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
tay
jsr Init_Dimensions_Maze
; player position returned in X and Y
jsr Build_Level
jsr player_init ; param: player pos in X and Y
level_was_built:
ldx ActorPositions + eACTORTYPES::PLAYER
ldy ActorPositions + eACTORTYPES::PLAYER + 1
jsr player_init
level_enter_end:
lda #FALSE
sta ExitLevel
lda NextLevel
sta CurrentLevel
rts
.define Player_XY ActorPositions + eACTORTYPES::PLAYER
level_exit:
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

55
src/world/level.inc Normal file
View File

@ -0,0 +1,55 @@
; 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/>.
.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 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

@ -0,0 +1,25 @@
; 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/>.
; 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

175
src/world/world.asm Normal file
View File

@ -0,0 +1,175 @@
; 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 "../common.inc"
.include "../actors/actors.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
; #TRUE if an object has been picked by the player
.export World_PickedObject
.export Tile_player_standing_actor
.define COORD_X ZERO_2_1
.define COORD_Y ZERO_2_2
.define OFFSET ZERO_2_2
.BSS
; The tile where the player stands
; 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
; @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
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 NEXT_TILE_XY
sty NEXT_TILE_XY+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 (PLAYER_XY), Y
; save the next tile
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 PLAYER_XY
sta PLAYER_XY+1
ldy #0
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 #eACTORTYPES::PLAYER
sta (PLAYER_XY), y
; restore the given locations
ldx NEXT_TILE_XY
ldy NEXT_TILE_XY+1
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
.BSS
.align 256
World: .res (WIDTH_WORLD) * (HEIGHT_WORLD)

31
src/world/world.inc Normal file
View File

@ -0,0 +1,31 @@
; Copyright (C) 2018-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/>.
; 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 $C0