From 261b7276b5839246001facf25e4f0323bd423d60 Mon Sep 17 00:00:00 2001 From: Christophe Meneboeuf Date: Mon, 21 Nov 2022 11:54:23 +0100 Subject: [PATCH] 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 --- Makefile | 19 +- README.md | 46 ++-- assets/tiles.psd | Bin 0 -> 45276 bytes doc/Doc.md | 55 ++++ escape.dsk | Bin 143360 -> 143360 bytes floppy/ESCAPE | Bin 0 -> 11847 bytes floppy/LEVELS.ACTS | Bin 0 -> 4224 bytes floppy/LEVELS.CONF | Bin 0 -> 391 bytes floppy/STATES | Bin 0 -> 14242 bytes scripts/add-to-disk.sh | 12 +- src/actors/actors.asm | 185 +++++++++++++ src/actors/actors.inc | 46 ++++ src/actors/reactions.asm | 103 +++++-- src/builder/actors.asm | 107 -------- src/builder/actors.inc | 35 ++- src/builder/actors_private.inc | 7 - src/builder/builder.asm | 205 +++++--------- src/builder/builder.inc | 1 - src/builder/maze.asm | 23 +- src/builder/rooms.asm | 28 +- src/builder/unite.asm | 39 ++- src/common.inc | 5 +- src/display.asm | 41 ++- src/display_map.asm | 31 ++- src/escape.cfg | 34 +-- src/game_loop.asm | 67 +++-- src/io/files.asm | 481 +++++++++++++++++++++++++++++++++ src/io/files.inc | 30 ++ src/io/textio.asm | 2 +- src/io/title.asm | 24 +- src/main.asm | 139 ++++++++-- src/math.inc | 6 +- src/memory.asm | 102 +++++-- src/memory.inc | 5 +- src/player.asm | 135 ++------- src/tiles.asm | 138 ++++++++-- src/world.asm | 154 ----------- src/world.inc | 34 --- src/world/level.asm | 339 +++++++++++------------ src/world/level.inc | 32 ++- src/world/level_private.inc | 27 +- src/world/world.asm | 93 ++++--- src/world/world.inc | 28 +- 43 files changed, 1767 insertions(+), 1091 deletions(-) create mode 100644 assets/tiles.psd create mode 100644 doc/Doc.md create mode 100644 floppy/ESCAPE create mode 100644 floppy/LEVELS.ACTS create mode 100644 floppy/LEVELS.CONF create mode 100644 floppy/STATES create mode 100644 src/actors/actors.asm create mode 100644 src/actors/actors.inc delete mode 100644 src/builder/actors.asm delete mode 100644 src/builder/actors_private.inc create mode 100644 src/io/files.asm create mode 100644 src/io/files.inc delete mode 100644 src/world.asm delete mode 100644 src/world.inc diff --git a/Makefile b/Makefile index 6cf4de3..a045b02 100644 --- a/Makefile +++ b/Makefile @@ -2,21 +2,22 @@ APPLE2_CL := $(CC65_HOME)/bin/cl65 APPLE2_SRC := src/main.asm src/math.asm src/memory.asm src/random.asm \ src/game_loop.asm src/display.asm src/tiles.asm src/player.asm \ src/world/world.asm src/world/level.asm \ - src/builder/builder.asm src/builder/actors.asm src/builder/rooms.asm src/builder/maze.asm src/builder/unite.asm \ - src/actors/reactions.asm \ + src/builder/builder.asm src/builder/rooms.asm src/builder/maze.asm src/builder/unite.asm \ + src/actors/reactions.asm src/actors/actors.asm \ src/debug.asm src/display_map.asm \ - src/io/title.asm src/io/textio.asm src/io/gr.asm + src/io/title.asm src/io/textio.asm src/io/gr.asm src/io/files.asm APPLE2_MAP := escape.map APPLE2_CFLAGS := -Oirs -v -t apple2 -vm --cpu 6502 -APPLE2_OUT := bin/escape.a2 +APPLE2_OUT := floppy/ESCAPE -all: directories apple2 - -directories: - mkdir -p bin +all: apple2 apple2: $(APPLE2_SRC) $(APPLE2_CL) -m $(APPLE2_MAP) -o $(APPLE2_OUT) $? $(APPLE2_CFLAGS) -C src/escape.cfg clean: $(SRC) - rm -f $(APPLE2_MAP) src/*.o src/builder/*.o src/io/*.o src/world/*.o src/actors/*.o gmon.out & rm -r bin/ + rm -f $(APPLE2_MAP) floppy/ESCAPE src/*.o src/builder/*.o src/io/*.o src/world/*.o src/actors/*.o gmon.out + +install: apple2 + ./scripts/add-to-disk.sh $(APPLE_COMMANDER) ./floppy escape.dsk + \ No newline at end of file diff --git a/README.md b/README.md index 9bbca51..6b31981 100644 --- a/README.md +++ b/README.md @@ -1,37 +1,39 @@ -# What is it? +## What is it? -**Escape** (working title) is a homebrew *Rogue-Like** game developped for the Apple II computers. +**Escape** (working title) is a homebrew *Rogue-Like** game developed for the Apple II computers. It is written in assembly and serves two purposes: 1. Be fun 2. Document the proccess of coding for the Apple II on [my blog](https://www.xtof.info): - - [A tile engine for the Apple II](https://www.xtof.info/an-hires-tile-engine-for-the-apple-ii.html) - - [Raycasting a Line of Sight](https://www.xtof.info/appleii-roguelike-line-of-sight.html) - - [Random level generation on Apple II](https://www.xtof.info/random-level-generation-on-apple-ii.html) + - [A tile engine for the Apple II](https://www.xtof.info/an-hires-tile-engine-for-the-apple-ii.html) + - [Raycasting a Line of Sight](https://www.xtof.info/appleii-roguelike-line-of-sight.html) + - [Random level generation on Apple II](https://www.xtof.info/random-level-generation-on-apple-ii.html) -# How to build +## How to build -## Building +### Prerequisites -Just type +* The build process relies on the assembler provided by the [CC65 compiler suite](https://github.com/cc65/cc65). + * Set the environment variable **CC65_HOME** to the root folder of CC65 + * Builds are guaranteed to be successful using version 2.19 (commit 555282497c3ecf8). They should also work with any subsequent versions. +* A makefile compatible with GNU Make is provided. +* [AppleCommander](http://applecommander.sourceforge.net/) is used to produce a disk image that can be loaded in any emulator. Apple Commander requires a Java Runtime. + * Export the variable **APPLE_COMMANDER** to the path of the jar file. - make +### How to build + +```bash +make +``` This will produce *bin/escape.a2* which is a binary executable for Apple's II PRODOS. -## Prerequisite in order to build: +```bash +make install +``` -The [cc65 compiler suite](https://github.com/cc65/cc65), with the environment variable *CC65_HOME* set to its folder +Will produce the executable binary and copy it along with all the required files into the floppy image *escape.dsk* -Tested OK with version V2.16 - Git be772c01 +### How to play -## Prerequisite in order to produce the disk image - -- Java Runtime -- [AppleCommander](http://applecommander.sourceforge.net/) - -## Embedding the Apple II' executable into the disk image - -Run - - scripts/add-to-disk.sh +You can navigate the levels using the IJKL keys and display a map by pressing TAB. diff --git a/assets/tiles.psd b/assets/tiles.psd new file mode 100644 index 0000000000000000000000000000000000000000..768dc9f711abbb72e32f8c745802dd013f9a82dc GIT binary patch literal 45276 zcmeHv2YeLO_W#|I-SiL=dJCb0>10Df3xpOS5Rw2&5jVS=uw=6vb~mAkhy_IX38D{C zRFop22+sycELcIo0#Z~^V*x<~k%X4E|L?goTNC!-d%pjBe%|iv%-nm@AO(9A5koJV@JmrQ1|cHKta@GNBvf5!84<9V7r zwe-blJ&X5rmhL~WxzKO$3C`unZU-Y0rga(+k1!+0MMu_zxHZXdI)moAk7dLzM?AX~!u_kk2TtaGU zYFvC`Tw-DjQp8y18m;O%F-A)lp%8mH!*mvnSzlt+n~YIZt~%dTY8@CIO%*wQV#A6{ z92FTYvAmJ78dGuH9Cb-tLTr3oQ<=0HN1l>Wvw@4I)x_xxx?-KtYC*n)Ci4N)tSm>? zCaWthZZfCEI=l=m5D{rIrzLN0i7qZjXEBwUHM-$tkfcjf!k5f2SxuH1rW>@|!4_K2 zJ4e850K`wrFzeJ-lR3|1G7J(rKHFYiR7M8+IUyyg=On#RYnpB8H6YG2i?auurRj#L zt-3+TsftNRj7jL1ml&Uxph`mYSWi9xSXllsM#8MUHPIe;Ay z=S=F7pDRaNrqNCPZTX&%UY8L#XICm>zA6G)K{xf$7oa3DKV-Ps;D4I z9g~`%N=Z^DrGT%qSL9Myql(6v^)NMRgG(A}ix!n7=4( zq=cCKcy)oUudZKyzk)=26-^Y=sH#zV3$$^riub>e8#=^VKSJ^ zSthM+P||?7rpQjUamkgLk&$gS73dARL6)46L!&Z>XQ&cVF?1!yCb$;klCH^e?8C

u_zs4J8yZy11cSNP!9`7Y=ru!^3VQ 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 A`Tzg` literal 0 HcmV?d00001 diff --git a/doc/Doc.md b/doc/Doc.md new file mode 100644 index 0000000..75146a7 --- /dev/null +++ b/doc/Doc.md @@ -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) +``` diff --git a/escape.dsk b/escape.dsk index 19b2a125a50fe3ad9f59bedc7b90d1237dc5b379..086abf142a5e4cbdac7924d429a6239dbeb394d9 100644 GIT binary patch delta 22699 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 delta 14511 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 literal 0 HcmV?d00001 diff --git a/floppy/LEVELS.ACTS b/floppy/LEVELS.ACTS new file mode 100644 index 0000000000000000000000000000000000000000..3977f89179aafa8f240a0c4684242f4ae852506b GIT binary patch literal 4224 zcmZ?zj|~WL@o}*6aByIg8x_}RaDi~H8i!fb#(Rg4GfKpO-#+qEiA39ZEWrA9UPsU zU0mJVJv_aQ&Q8?GcvQXb8_?Y3kr*hOG?Yi zD=Mq1YijH2vAbACR6^+geM$hf3)R0xRcGO>qbLhGz6#+0?6er KFUUMPw|@c4Dj|gc literal 0 HcmV?d00001 diff --git a/floppy/LEVELS.CONF b/floppy/LEVELS.CONF new file mode 100644 index 0000000000000000000000000000000000000000..fb09e93ed726ea2c7ec90bfce9a1c425ba5090d8 GIT binary patch literal 391 scmZQ(5Me+9jEqc3Jo+#h6_D&aeo{*Itb$2hB+CMlvI!>RQo}FK0F0Za{Ztt?W`}{-U@#*>H^{x2+@%i=rLxP&l Q?|*p`)O-S!2B>s`zh&BTT>t<8 literal 0 HcmV?d00001 diff --git a/scripts/add-to-disk.sh b/scripts/add-to-disk.sh index 29d4b90..4e755d7 100644 --- a/scripts/add-to-disk.sh +++ b/scripts/add-to-disk.sh @@ -6,7 +6,7 @@ set -e if (( $# != 3 )); then echo "Bad number of arguments" - echo "usage: add_to_disk.sh PATH_TO_APPLECOMMANDER.jar PATH_TO_BINARY.a2 PATH_TO_DISK" + echo "usage: add_to_disk.sh PATH_TO_APPLECOMMANDER.jar PATH_TO_FLOPPYDIR PATH_TO_DISK" exit fi @@ -17,9 +17,15 @@ fi echo " . removing previous instance of ESCAPE from the disk" java -jar ${1} -d ${3} ESCAPE java -jar ${1} -d ${3} ESCAPE.SYSTEM +java -jar ${1} -d ${3} LEVELS.CONF +java -jar ${1} -d ${3} LEVELS.ACTS +java -jar ${1} -d ${3} STATES -echo " .. adding ESCAPE and its loader to the disk" -java -jar ${1} -cc65 ${3} ESCAPE BIN < ${2} +echo " .. adding files to the disk" +java -jar ${1} -as ${3} ESCAPE BIN < ${2}/ESCAPE java -jar ${1} -p ${3} ESCAPE.SYSTEM SYS < ${CC65_HOME}/target/apple2/util/loader.system +java -jar ${1} -p ${3} LEVELS.CONF BIN < ${2}/LEVELS.CONF +java -jar ${1} -p ${3} LEVELS.ACTS BIN < ${2}/LEVELS.ACTS +java -jar ${1} -p ${3} STATES BIN < ${2}/STATES echo "DONE." diff --git a/src/actors/actors.asm b/src/actors/actors.asm new file mode 100644 index 0000000..a9644a6 --- /dev/null +++ b/src/actors/actors.asm @@ -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+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 \ No newline at end of file diff --git a/src/actors/actors.inc b/src/actors/actors.inc new file mode 100644 index 0000000..782ab5c --- /dev/null +++ b/src/actors/actors.inc @@ -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 + + + diff --git a/src/actors/reactions.asm b/src/actors/reactions.asm index b64e379..6dd583b 100644 --- a/src/actors/reactions.asm +++ b/src/actors/reactions.asm @@ -13,7 +13,7 @@ ; You should have received a copy of the GNU General Public License ; along with this program. If not, see . - +.include "actors.inc" .include "../world/level.inc" .include "../io/textio.inc" .include "../common.inc" @@ -22,20 +22,39 @@ .export Reactions_msb .export ReactionStairUp .export ReactionStairDown +.export ReactionMap + +.import ActorPositions +.import World_PickedObject .DATA -STR_REATION_WALL: ASCIIZ "YOU HIT A WALL" -STR_REATION_STAIR_UP: ASCIIZ "YOU GO UPSTAIRS TO THE PREVIOUS LEVEL" -STR_REATION_STAIR_DOWN: ASCIIZ "YOU GO DOWNSTAIRS TO THE NEXT LEVEL" +STR_REACTION_WALL: ASCIIZ "YOU HIT A WALL" +STR_REACTION_STAIR_UP: ASCIIZ "YOU GO UPSTAIRS TO TO THE NEXT LEVEL" +STR_REACTION_STAIR_DOWN: ASCIIZ "YOU GO DOWNSTAIRS THE PREVIOUS LEVEL" +STR_REACTION_MAP: ASCIIZ "YOU FOUND A MAP!" +STR_REACTION_RAT: ASCIIZ "YOU ATTACK THE RAT" +STR_REACTION_SPIDER: ASCIIZ "YOU ATTACK THE SPIDER" +STR_REACTION_SERPENT: ASCIIZ "YOU ATTACK THE SERPENT" .align 256 ; functions address seperated in LSB / MSB to use the same X/Y offset +; They must be in the very same order as the actor's types Reactions_lsb: -.byte 0, ReactionFloor, >ReactionFloor, >ReactionFloor, >ReactionFloor, >ReactionFloor, >ReactionFloor, >ReactionStairDown -.byte >ReactionStairUp, >ReactionWall, >ReactionWall, >ReactionWall, >ReactionWall, 0, 0, 0 -.byte 0, 0, 0, 0, 0, 0, 0, 0 +; player +.byte 0 +; floors +.byte >ReactionFloor, >ReactionFloor, >ReactionFloor, >ReactionFloor, >ReactionFloor, >ReactionFloor +; walls +.byte >ReactionWall, >ReactionWall, >ReactionWall, >ReactionWall +; stairs +.byte >ReactionStairDown, >ReactionStairUp +; items +.byte >ReactionMap +; monsters +.byte >ReactionRat, >ReactionSpider, >ReactionSerpent + ; others .byte 0, 0, 0, 0, 0, 0, 0, 0 .byte 0, 0, 0, 0, 0, 0, 0, 0 .byte 0, 0, 0, 0, 0, 0, 0, 0 @@ -99,35 +129,70 @@ Reactions_msb: .byte 0, 0, 0, 0, 0, 0, 0, 0 .byte 0, 0, 0, 0, 0, 0, 0, 0 .byte 0, 0, 0, 0, 0, 0, 0, 0 +.byte 0, 0, 0, 0, 0, 0, 0 .CODE + ReactionFloor: - lda TRUE + lda #TRUE rts ReactionWall: - PRINT STR_REATION_WALL - lda FALSE + PRINT STR_REACTION_WALL + lda #FALSE rts ReactionStairUp: - PRINT STR_REATION_STAIR_UP + PRINT STR_REACTION_STAIR_UP lda CurrentLevel sta NextLevel inc NextLevel - lda TRUE + lda #TRUE sta ExitLevel - lda FALSE + lda #FALSE rts ReactionStairDown: - PRINT STR_REATION_STAIR_DOWN + PRINT STR_REACTION_STAIR_DOWN lda CurrentLevel sta NextLevel dec NextLevel - lda TRUE + lda #TRUE sta ExitLevel - lda FALSE + lda #FALSE + rts + +; @param actor_id in X +ReactionMap: + + ; index of &ActorPositions[actor_id] + txa + asl + tax + lda #UNDEF + sta ActorPositions, X + sta ActorPositions+1, X + + PRINT STR_REACTION_MAP + + lda #TRUE + sta World_PickedObject + + rts + +ReactionRat: + PRINT STR_REACTION_RAT + lda #FALSE + rts + +ReactionSpider: + PRINT STR_REACTION_SPIDER + lda #FALSE + rts + +ReactionSerpent: + PRINT STR_REACTION_SERPENT + lda #FALSE rts diff --git a/src/builder/actors.asm b/src/builder/actors.asm deleted file mode 100644 index 804b532..0000000 --- a/src/builder/actors.asm +++ /dev/null @@ -1,107 +0,0 @@ -.include "../common.inc" -.include "../random.inc" -.include "../memory.inc" -.include "../math.inc" -.include "../world/world.inc" -.include "actors_private.inc" - -.import Rooms -.import World -.import Compute_Maze_Addr - -; code -.export Place_Actors -; data -.export ActiveActor_Tiles - -.DATA - -ActiveActor_Tiles: .byte ACTORS::STAIR_UP, ACTORS::STAIR_DOWN, ACTORS::FLOOR_1 ; DEBUg: placeholder for future map -.CODE - -.define PTR_ROOM ZERO_2_1 ; 2 bytes -.define PTR_TILE ZERO_2_1 ; 2 bytes -; the two following defines must be the same as in Build_Level -.define ROOM_X ZERO_3 -.define ROOM_Y ZERO_2_4 -.define ROOM_W ZERO_2_5 -.define ROOM_H ZERO_2_6 -.define NB_ROOMS ZERO_9_9 -.define ACTOR ZERO_9_10 -; A : ACTOR -; X : NB_ROOMS -Place_Actors: - - sta ACTOR - stx NB_ROOMS - -loop_find_location: - - jsr Random8 - ldx NB_ROOMS - jsr Modulus - - ; sizeof(room_t) == 4 - asl - asl - clc - adc #Rooms - sta PTR_ROOM+1 - - ldy #0 - lda (PTR_ROOM), Y - sta ROOM_H - iny - lda (PTR_ROOM), Y - sta ROOM_W - iny - lda (PTR_ROOM), Y - sta ROOM_X - iny - lda (PTR_ROOM), Y - sta ROOM_Y - - ; x = room->x + rand() % (room->width - 2) + 1; - sec - lda ROOM_W - sbc #2 - sta ROOM_W - jsr Random8 - ldx ROOM_W - jsr Modulus - clc - adc ROOM_X - adc #1 - sta ROOM_X - - ; y = room->y + rand() % (room->height - 2) + 1; - sec - lda ROOM_H - sbc #2 - sta ROOM_H - jsr Random8 - ldx ROOM_H - jsr Modulus - clc - adc ROOM_Y - adc #1 - sta ROOM_Y - tay - - ldx ROOM_X - jsr Compute_Maze_Addr - stx PTR_TILE - sta PTR_TILE+1 - ldy #0 - lda (PTR_TILE), Y - cmp #ACTORS::FLOOR_2 - bne loop_find_location - - - lda ACTOR - sta (PTR_TILE), Y - - rts \ No newline at end of file diff --git a/src/builder/actors.inc b/src/builder/actors.inc index 2103e95..0fe6cb6 100644 --- a/src/builder/actors.inc +++ b/src/builder/actors.inc @@ -1,7 +1,32 @@ -.include "actors_private.inc" +.define NB_ACTORS_MAX 128 -; code -.import Place_Actors -; data -.import ActiveActor_Tiles + +.enum ACTORS + + PLAYER = 0 + ; FLOOR + FLOOR_1 = 1 + FLOOR_2 ; FLOOR BY DEFAULT + FLOOR_3 + FLOOR_4 + FLOOR_5 + FLOOR_6 + STAIR_DOWN + ; OBJECT + MAP + ; WALLS + STAIR_UP + WALKABLE = STAIR_UP ; Player won't be allowed to go on anything > WALKABLE + + NOT_TRANSPARENT = STAIR_UP + NOT_WALKABLE + + WALL_1 = NOT_WALKABLE + WALL_2 + + UNKNOWN + + NB_ACTORS + +.endenum \ No newline at end of file diff --git a/src/builder/actors_private.inc b/src/builder/actors_private.inc deleted file mode 100644 index d262bf6..0000000 --- a/src/builder/actors_private.inc +++ /dev/null @@ -1,7 +0,0 @@ -; @brief All kind of reactive actors that can be in a level -.enum eACTORSREACTIVE - AA_STAIRUP = 0 - AA_STAIRDOWN - AA_MAP - AA_NB -.endenum diff --git a/src/builder/builder.asm b/src/builder/builder.asm index d77316b..6735415 100644 --- a/src/builder/builder.asm +++ b/src/builder/builder.asm @@ -20,7 +20,8 @@ .include "rooms.inc" .include "maze.inc" .include "unite.inc" -.include "actors.inc" +.include "../common.inc" +.include "../actors/actors.inc" .include "../io/textio.inc" .include "../math.inc" .include "../monitor.inc" @@ -28,12 +29,15 @@ .include "../world/world.inc" .include "../world/level.inc" -.import World +; code .import Random8 .import Grow_Maze ; to patch .import Compute_Maze_Addr +.import Place_Actors +; data +.import World +.import Tile_player_standing_actor -.export Get_Size_Maze .export Init_Dimensions_Maze .export Build_Level @@ -69,56 +73,11 @@ STR_DEADENDS: ASCIIZ "FILLING DEAD ENDS..." STR_UNITE: ASCIIZ "UNITING THE ROOMS..." STR_ACTORS: ASCIIZ "PLACING ACTORS..." + + .CODE -; DEPRECATED!!! -; @brief Asks for the size of the maze -; Returns Width in X and Height in Y -Get_Size_Maze: - - ; User input - PRINT STR_SIZE_MAZE_1 -choice_size_maze: - PRINT STR_SIZE_MAZE_2 - jsr Cin_Char - - ; switch case over the input - tst_tiny: - cmp #$C1 - bne tst_small - ldx #LEVELSIZE::TINY - ldy #LEVELSIZE::TINY - rts - tst_small: - cmp #$C2 - bne tst_medium - ldx #LEVELSIZE::SMALL - ldy #LEVELSIZE::SMALL - rts - tst_medium: - cmp #$C3 - bne tst_big - ldx #LEVELSIZE::NORMAL - ldy #LEVELSIZE::NORMAL - rts - tst_big: - cmp #$C4 - bne tst_huge - ldx #LEVELSIZE::BIG - ldy #LEVELSIZE::BIG - rts - tst_huge: - cmp #$C5 - bne bad_size - ldx #LEVELSIZE::HUGE - ldy #LEVELSIZE::HUGE - rts - bad_size: - PRINT STR_SIZE_MAZE_3 - jmp choice_size_maze - - ; @brief Fills border walls ; @param type of the "wall" in A ; destroys ZERO_2_1, ZERO_2_2 @@ -198,15 +157,18 @@ Init_Dimensions_Maze: ; @return player position in X and Y .define DST_WORLD World .define ADDR_TO_PATCH init_world_line + 3 -.define NB_ROOMS ZERO_9_9 +.define NB_ROOMS ZERO_9_9 ; use same location as Place_Actors Build_Level: - ; Filling World with ACTORS::WALL_1 + lda #UNDEF + sta Tile_player_standing_actor + + ; Filling World with eACTORTYPES::WALL_1 ldy #HEIGHT_WORLD init_world: ldx #0 init_world_line: - lda #ACTORS::WALL_1 + lda #eACTORTYPES::WALL_1 sta DST_WORLD, x inx cpx #WIDTH_WORLD @@ -225,20 +187,21 @@ Build_Level: lda #DST_WORLD - sta ADDR_TO_PATCH+1 + sta ADDR_TO_PATCH+1 PRINT STR_ROOMS + lda #MAX_NB_ROOMS+1 jsr Carve_Rooms sta NB_ROOMS - lda #ACTORS::FLOOR_1 - jsr _build_fences + lda #eACTORTYPES::FLOOR_1 + jsr _build_fences PRINT STR_MAZE jsr Grow_Maze - lda #ACTORS::WALL_1 + lda #eACTORTYPES::WALL_1 jsr _build_fences PRINT STR_DOORS @@ -252,50 +215,51 @@ Build_Level: PRINT STR_UNITE jsr Unite_Rooms - - PRINT STR_ACTORS + ; the two following defines must be the same as in Place_Actors .define POS_X ZERO_3 ; ROOM_X in Place_Actors .define POS_Y ZERO_2_4 ; ROOM_Y in Place_Actors .define POS_STARDOWN_X ZERO_5_1 .define POS_STARDOWN_Y ZERO_5_2 - .define ACTOR ZERO_4_1 .define ACTOR_NB ZERO_4_2 - .define CURR_ACTOR_OFFSET ZERO_4_3 - .define POS_PLAYER_OFFSET ZERO_4_4 - .define LEVEL_CONF_OFFSET ZERO_5_3 - .define ADDR_ACTOR ZERO_4_3 ; 2 bytes + .define ACTOR_ID ZERO_9_1 ; use same location as Place_Actors + .define ACTOR_TYPE ZERO_9_2 ; use same location as Place_Actors + .define CURR_ACTOR_OFFSET ZERO_4_3 + .define ADDR_LEVEL_CONF ZERO_5_3 ; 2 bytes + .define ADDR_ACTOR ZERO_4_3 ; 2 bytes - lda #0 - sta ACTOR - ldx NextLevel - stx FAC1 - ldx #SIZEOF_CONF_LEVEL - stx FAC2 - jsr mul8 ; A = offset to level conf - txa - sta LEVEL_CONF_OFFSET + ; place actors + PRINT STR_ACTORS + ; offset to level conf + + lda NextLevel + jsr level_get_config_offset + pha clc - adc #7 ; A = offset to pos_player_enter - sta POS_PLAYER_OFFSET - tax - inx - inx ; offset to actors[AA_NB] - loop_actors: - stx CURR_ACTOR_OFFSET - lda Levels, X ; actors[AA_NB] + txa + adc #LevelConfigs + sta ADDR_LEVEL_CONF+1 + lda #eACTORTYPES::LAST_STATIC + 1 ; 1st dynamic actor id + sta ACTOR_ID + sta ACTOR_TYPE + tay + iny + iny ; offset to actors[ACTOR_ID] in level conf + loop_actors: ; loop over actors from conf + sty CURR_ACTOR_OFFSET + lda (ADDR_LEVEL_CONF), Y sta ACTOR_NB - loop_actor_nb: - beq end_loop_actor_nb + loop_actor_id: + beq end_loop_actor_id - ldx ACTOR - lda ActiveActor_Tiles, X - ldx NB_ROOMS - jsr Place_Actors + jsr Place_Actors ; save stair down position - lda ACTOR - cmp #eACTORSREACTIVE::AA_STAIRDOWN + lda ACTOR_TYPE + cmp #eACTORTYPES::STAIR_DOWN bne not_stair_down lda POS_X sta POS_STARDOWN_X @@ -303,31 +267,29 @@ Build_Level: sta POS_STARDOWN_Y not_stair_down: + inc ACTOR_ID dec ACTOR_NB ; next - jmp loop_actor_nb - end_loop_actor_nb: + lda ACTOR_NB + jmp loop_actor_id + end_loop_actor_id: - ldx CURR_ACTOR_OFFSET - inx - inc ACTOR - ldy ACTOR - cpy #eACTORSREACTIVE::AA_NB + ldy CURR_ACTOR_OFFSET + iny + inc ACTOR_TYPE + lda ACTOR_TYPE + cmp #(NB_ACTORS_MAX-1) bne loop_actors - + ; Set the 1st position of the player in the level - ldx POS_PLAYER_OFFSET - lda Levels, X - cmp #$FF - bne not_first_entry - ; Very first entrance in the level - lda NextLevel - cmp #0 - bne not_first_level - ; Special case: first level - ; TODO avoid non empty floor... - ldx Rooms+2 ; Rooms[0].x - ldy Rooms+3 ; Rooms[0].y - rts + ; offset to level state + lda NextLevel + cmp #0 + bne not_first_level + ; Special case: first level + ; TODO avoid non empty floor... + ldx Rooms+2 ; Rooms[0].x + ldy Rooms+3 ; Rooms[0].y + rts not_first_level: ldx POS_STARDOWN_X ldy POS_STARDOWN_Y @@ -346,7 +308,7 @@ Build_Level: ; if (World[pos_stair_down.y][pos_stair_down.x - 1] == FLOOR_2) ldy #(WIDTH_WORLD - 1) lda (ADDR_ACTOR), Y - cmp #ACTORS::FLOOR_2 + cmp #eACTORTYPES::FLOOR_2 bne not_x_minus ldy POS_STARDOWN_Y dex @@ -355,7 +317,7 @@ Build_Level: ; if (World[pos_stair_down.y - 1][pos_stair_down.x] == FLOOR_2) ldy #0 lda (ADDR_ACTOR), Y - cmp #ACTORS::FLOOR_2 + cmp #eACTORTYPES::FLOOR_2 bne not_y_minus ldy POS_STARDOWN_Y dey @@ -364,7 +326,7 @@ Build_Level: ; if (World[pos_stair_down.y + 1][pos_stair_down.x] == FLOOR_2) ldy #(WIDTH_WORLD * 2) lda (ADDR_ACTOR), Y - cmp #ACTORS::FLOOR_2 + cmp #eACTORTYPES::FLOOR_2 bne not_y_plus ldy POS_STARDOWN_Y iny @@ -372,23 +334,6 @@ Build_Level: not_y_plus: ldy POS_STARDOWN_Y inx - rts - not_first_entry: - pha ; pos_player_enter.x - inx - lda Levels, X ; pos_player_enter.y - tay - pla - tax - rts - - - ; ldx NB_ROOMS - ; lda #ACTORS::STAIR_DOWN - ; jsr Place_Actors - ; lda #ACTORS::STAIR_UP - ; ldx NB_ROOMS - ; jsr Place_Actors rts diff --git a/src/builder/builder.inc b/src/builder/builder.inc index bf6e858..ef779a6 100644 --- a/src/builder/builder.inc +++ b/src/builder/builder.inc @@ -13,7 +13,6 @@ ; You should have received a copy of the GNU General Public License ; along with this program. If not, see . -.import Get_Size_Maze .import Init_Dimensions_Maze .import Build_Level .import Rooms \ No newline at end of file diff --git a/src/builder/maze.asm b/src/builder/maze.asm index 1c1f80f..4e33b63 100644 --- a/src/builder/maze.asm +++ b/src/builder/maze.asm @@ -18,6 +18,7 @@ .include "../math.inc" .include "../common.inc" .include "../world/world.inc" +.include "../actors/actors.inc" .export Grow_Maze @@ -121,7 +122,7 @@ .macro ISWALKABLE offset ldy offset lda (PTR_NEW_TILE),Y - cmp #ACTORS::WALKABLE+1 + cmp #eACTORTYPES::LAST_FLOOR+1 bcc cannot_carve .endmacro @@ -139,27 +140,27 @@ ldy OFFSET_NIL lda (PTR_NEW_TILE),Y - cmp #ACTORS::WALKABLE + cmp #eACTORTYPES::LAST_FLOOR bcc end_loop_stack ldy OFFSET_UP lda (PTR_NEW_TILE),Y - cmp #ACTORS::WALKABLE + cmp #eACTORTYPES::LAST_FLOOR bcc end_loop_stack ldy OFFSET_RIGHT lda (PTR_NEW_TILE),Y - cmp #ACTORS::WALKABLE + cmp #eACTORTYPES::LAST_FLOOR bcc end_loop_stack ldy OFFSET_DOWN lda (PTR_NEW_TILE),Y - cmp #ACTORS::WALKABLE + cmp #eACTORTYPES::LAST_FLOOR bcc end_loop_stack ldy OFFSET_LEFT lda (PTR_NEW_TILE),Y - cmp #ACTORS::WALKABLE + cmp #eACTORTYPES::LAST_FLOOR bcc end_loop_stack .endmacro @@ -194,7 +195,7 @@ loop_grow_maze: ; carve ldy #WIDTH_WORLD - lda #ACTORS::FLOOR_1 + lda #eACTORTYPES::FLOOR_1 sta (PTR_NEW_TILE),Y @@ -236,7 +237,7 @@ loop_grow_maze: carve_the_tile: ; carve the tile ldy #0 - lda #ACTORS::FLOOR_1 + lda #eACTORTYPES::FLOOR_1 sta (PTR_NEW_TILE),Y jmp loop_stack end_loop_stack: @@ -438,7 +439,7 @@ _follow_dead_end: loop_follow: ldy #WIDTH_WORLD - lda #ACTORS::WALL_1 + lda #eACTORTYPES::WALL_1 sta (PTR_TILE), Y lda PTR_NEXT_TILE @@ -462,7 +463,7 @@ _follow_dead_end: rts -.define ADD_FACTOR ZERO_4_1 +.define ADD_FACTOR ZERO_4_3 ; REM: PTR_TILE is already offsetted by -WIDTH_WORLD ; for easy access to adjacent tiles by indirect indexing ; Returns : NB_WALLS >= 3 if it is a dead end @@ -474,7 +475,7 @@ _is_tile_dead_end: sty ADD_FACTOR ; Returns if the tile is a wall - lda #ACTORS::WALKABLE + lda #eACTORTYPES::LAST_FLOOR cmp (PTR_TILE), Y bcc end_tst_up_tile diff --git a/src/builder/rooms.asm b/src/builder/rooms.asm index f91942d..a9c254c 100644 --- a/src/builder/rooms.asm +++ b/src/builder/rooms.asm @@ -19,6 +19,7 @@ .include "../math.inc" .include "../common.inc" .include "../world/world.inc" +.include "../actors/actors.inc" .export Carve_Rooms .export Connect_Rooms @@ -33,6 +34,7 @@ .BSS ; Configration to build rooms +; FIXME??? CA65 will locate this struct at address 0 !!! .struct Config_Room width_min .byte width_max .byte @@ -73,18 +75,17 @@ Carve_Rooms: lda NB_ROOMS_OK ; NB_ROOMS_OK*sizeof(room_t) -> X asl asl - tax + tax jsr _Build_Room lda NB_ROOMS_OK jsr _Is_intersecting - cmp TRUE ; not intersecting with another room? + cmp #TRUE ; not intersecting with another room? beq loop_rooms - + inc NB_ROOMS_OK - clc - bcc loop_rooms + jmp loop_rooms end_loop_rooms: @@ -106,8 +107,7 @@ Carve_Rooms: end_loop_draw_rooms: - - lda NB_ROOMS_OK + lda NB_ROOMS_OK rts .undefine NB_ATTEMPTS @@ -142,7 +142,7 @@ _Draw_Room: lda Rooms+1, X ; room->width sta LINE_LENGTH loop_draw_line: - lda #ACTORS::FLOOR_1 + lda #eACTORTYPES::FLOOR_1 ldy #0 loop_draw_tile: sta (ADDR_WORLD), Y @@ -272,7 +272,7 @@ _Is_intersecting: cmp #0 bne compare ; first room - lda FALSE + lda #FALSE clc bcc end_intersecting ; branch always @@ -308,7 +308,7 @@ compare: cmp Rooms+3, Y ; room->y bcc false ; branch if new_room->y + new_room->height < room->y ; all test are true: rooms are intersecting - lda TRUE ; return value + lda #TRUE ; return value clc bcc end_intersecting @@ -320,7 +320,7 @@ compare: dec NB_ROOMS bne loop_intersecting - lda FALSE ; no room intersects + lda #FALSE ; no room intersects end_intersecting: rts @@ -554,7 +554,7 @@ Connect_Rooms: bcc loop_first_door ; nb_walkable < 2 inc NB_DOORS ldy #WIDTH_WORLD - lda #ACTORS::FLOOR_1 + lda #eACTORTYPES::FLOOR_1 sta (PTR_TILE), Y ; # Opening the other doors @@ -597,7 +597,7 @@ Connect_Rooms: bcc loop_other_doors ; always jump as the previous bcs failed carve_a_door: ldy #WIDTH_WORLD - lda #ACTORS::FLOOR_1 + lda #eACTORTYPES::FLOOR_1 sta (PTR_TILE), Y inc NB_DOORS jmp loop_other_doors @@ -621,7 +621,7 @@ Connect_Rooms: _nb_walkable: lda #0 sta NB_WALKABLE - lda #ACTORS::FLOOR_1 + lda #eACTORTYPES::FLOOR_1 tst_up: ldy #0 cmp (PTR_TILE), Y diff --git a/src/builder/unite.asm b/src/builder/unite.asm index d7834fe..52ee108 100644 --- a/src/builder/unite.asm +++ b/src/builder/unite.asm @@ -23,6 +23,7 @@ .include "../math.inc" .include "../common.inc" .include "../world/world.inc" +.include "../actors/actors.inc" .import World .import Rooms @@ -33,9 +34,7 @@ .export Unite_Rooms -.BSS -.DATA .CODE @@ -62,7 +61,7 @@ _Flood_Fill : ldy #0 cmp (PTR_TILE), Y ; if (*ptr_tile != replaced) return; beq fill_1 - lda FALSE + lda #FALSE rts fill_1: @@ -114,7 +113,7 @@ fill_1: lda FILL_NR sta (PTR_TILE_LOCAL),Y ; *(++ptr_queue) = tile_w - ADD16 PTR_QUEUE, #2 + ADD16 PTR_QUEUE, #2, #0 clc lda #1 adc PTR_TILE_LOCAL @@ -136,7 +135,7 @@ fill_1: lda FILL_NR sta (PTR_TILE_LOCAL),Y ; *(++ptr_queue) = tile_tile_east - ADD16 PTR_QUEUE, #2 + ADD16 PTR_QUEUE, #2, #0 sec lda PTR_TILE_LOCAL sbc #1 @@ -157,7 +156,7 @@ fill_1: lda FILL_NR sta (PTR_TILE_LOCAL),Y ; *(++ptr_queue) = tile_tile_north - ADD16 PTR_QUEUE, #2 + ADD16 PTR_QUEUE, #2, #0 sec lda PTR_TILE_LOCAL sbc #WIDTH_WORLD @@ -178,7 +177,7 @@ fill_1: lda FILL_NR sta (PTR_TILE_LOCAL),Y ; *(++ptr_queue) = tile_tile_south - ADD16 PTR_QUEUE, #2 + ADD16 PTR_QUEUE, #2, #0 clc lda #WIDTH_WORLD adc PTR_TILE_LOCAL @@ -194,7 +193,7 @@ fill_1: end_fill: - lda TRUE + lda #TRUE rts @@ -202,7 +201,7 @@ end_fill: .define ROOM_NR ZERO_3 .define SAVE_X ZERO_4_1 .define PTR_ROOM ZERO_4_2 ; 2 bytes -.define ZONE_0 ACTORS::FLOOR_1 ; 1st useful zone: ZONE_1 +.define ZONE_0 eACTORTYPES::FLOOR_1 ; 1st useful zone: ZONE_1 Unite_Rooms: ; *** flood fill room to identify separated zones *** @@ -226,13 +225,13 @@ Unite_Rooms: ldx ZONE_NR lda #ZONE_0 jsr _Flood_Fill - cmp TRUE + cmp #TRUE bne loop_flood_next inc ZONE_NR loop_flood_next: ;next tile - ADD16 PTR_TILE, #1 + ADD16 PTR_TILE, #1, #0 ; end line? inc CPT_X ldx CPT_X @@ -241,7 +240,7 @@ Unite_Rooms: ldx #0 stx CPT_X ; next - ADD16 PTR_TILE, #1 + ADD16 PTR_TILE, #1, #0 ; the end? inc CPT_Y ldy CPT_Y @@ -460,7 +459,7 @@ _Connect_Room: while_1: ; ptr_room += ix patch_ix1: - ADD16 PTR_ROOM, #1 + ADD16 PTR_ROOM, #1, #0 ; d += dy2 clc lda DELTA_Y_2 @@ -474,7 +473,7 @@ _Connect_Room: lda (PTR_ROOM), Y ; Y = 0 cmp ZONE_NR beq continue_1a - cmp #ACTORS::WALKABLE + cmp #eACTORTYPES::LAST_FLOOR beq end bpl continue_1a jmp end @@ -484,7 +483,7 @@ _Connect_Room: sta (PTR_ROOM), Y ; Y = 0 ; ptr_room += iy patch_iy1: - ADD16 PTR_ROOM, #WIDTH_WORLD + ADD16 PTR_ROOM, #WIDTH_WORLD, #0 ; d -= dx2 sec lda D @@ -495,7 +494,7 @@ _Connect_Room: lda (PTR_ROOM), Y ; Y = 0 cmp ZONE_NR beq continue_1b - cmp #ACTORS::WALKABLE + cmp #eACTORTYPES::LAST_FLOOR beq end bpl continue_1b jmp end @@ -517,7 +516,7 @@ _Connect_Room: while_2: ; ptr_room += iy patch_iy2: - ADD16 PTR_ROOM, #WIDTH_WORLD + ADD16 PTR_ROOM, #WIDTH_WORLD, #0 ; d += dx2 clc lda DELTA_X_2 @@ -531,7 +530,7 @@ _Connect_Room: lda (PTR_ROOM), Y ; Y = 0 cmp ZONE_NR beq continue_2a - cmp #ACTORS::WALKABLE + cmp #eACTORTYPES::LAST_FLOOR beq end bpl continue_2a jmp end @@ -541,7 +540,7 @@ _Connect_Room: sta (PTR_ROOM), Y ; Y = 0 ; ptr_room += ix; patch_ix2: - ADD16 PTR_ROOM, #1 + ADD16 PTR_ROOM, #1, #0 ; d -= dy2 sec lda D @@ -552,7 +551,7 @@ _Connect_Room: lda (PTR_ROOM), Y ; Y = 0 cmp ZONE_NR beq continue_2b - cmp #ACTORS::WALKABLE + cmp #eACTORTYPES::LAST_FLOOR beq end bpl continue_2b jmp end diff --git a/src/common.inc b/src/common.inc index 0393bbf..72ff6c6 100644 --- a/src/common.inc +++ b/src/common.inc @@ -13,5 +13,6 @@ ; You should have received a copy of the GNU General Public License ; along with this program. If not, see . -.define TRUE #1 -.define FALSE #0 +.define TRUE 1 +.define FALSE 0 +.define UNDEF $FF \ No newline at end of file diff --git a/src/display.asm b/src/display.asm index 3e0e191..d65bea2 100644 --- a/src/display.asm +++ b/src/display.asm @@ -15,11 +15,13 @@ ; along with this program. If not, see . .include "world/world.inc" +.include "actors/actors.inc" .include "display.inc" .include "tiles.inc" .include "math.inc" .include "memory.inc" .include "monitor.inc" +.include "common.inc" ; Init the view. To be called before anything else! @@ -44,6 +46,8 @@ .import Compute_Maze_Addr .import World .import Player_XY +.import ActorTransparent +.import ActorTypes .import DBG_TRACE .import DBG_TRACES @@ -97,20 +101,6 @@ loop_view_init: rts -; this routines populates View_Future, without any LOS -_dbg_build_view: - - lda #0 - ldx #(GRID_WIDTH * GRID_HEIGHT - 1) - loop_build_view: - lda #ACTORS::PLAYER - sta View_Future,X - dex - bne loop_build_view - sta View_Future,X - - rts - ; this routine will create the view and populate View_Future ; destroys ZERO_4_3, ZERO_4_4, ZERO_5_1, ZERO_5_2, ZERO_5_3 ; ZERO_5_4, ZERO_5_5, ZERO_5_6, ZERO_7_1, ZERO_7_2 @@ -120,7 +110,7 @@ _build_view: lda #0 ldx #(GRID_WIDTH * GRID_HEIGHT - 1) loop_init_view: - lda #ACTORS::UNKNOWN + lda #eACTORTYPES::UNKNOWN sta View_Future,X dex bne loop_init_view @@ -129,7 +119,7 @@ _build_view: ; 2 - Player .define OFFSET_PLAYER_IN_VIEW PLAYER_X+PLAYER_Y*GRID_WIDTH ldx #(OFFSET_PLAYER_IN_VIEW) - lda #ACTORS::PLAYER + lda #eACTORTYPES::PLAYER sta View_Future,X ; 3 - Casting rays @@ -140,6 +130,7 @@ _build_view: .define SRC_TILE_IN_WORLD ZERO_5_2 ; 2 bytes .define PTR_RAY ZERO_5_4 ; 2 bytes .define TMP ZERO_5_6 + .define TMP2 ZERO_7_1 ; loading ptr_rays - 1 as it will be incremented @@ -197,15 +188,21 @@ _build_view: iny sty TMP lda (PTR_RAY),Y ; offset_view - tax + sta TMP2 ldy #0 - lda (SRC_TILE_IN_WORLD),Y - sta View_Future,X + lda (SRC_TILE_IN_WORLD), Y + ; sta View_Future, X ; ptr tile in view future ldy TMP iny - ; break if non-transparent - cmp #ACTORS::NOT_TRANSPARENT - bcs end_loop_ray + ; break if non-transparent + tax + lda ActorTypes, X + ldx TMP2 + sta View_Future, X + tax + lda ActorTransparent, X + cmp #TRUE + bne end_loop_ray ; loop if tiles are left in the ray ldx NB_TILES_IN_RAY_LEFT diff --git a/src/display_map.asm b/src/display_map.asm index 07c6e28..d63cc4a 100644 --- a/src/display_map.asm +++ b/src/display_map.asm @@ -16,10 +16,11 @@ .include "world/world.inc" +.include "actors/actors.inc" +.include "io/gr.inc" .include "memory.inc" .include "math.inc" .include "monitor.inc" -.include "io/gr.inc" ; inits display of map .export Display_Map_Init @@ -201,11 +202,12 @@ quit: rts .import World -.define SRC_LINE_UP ZERO_7_1 +.define SRC_LINE_UP ZERO_7_1 .define SRC_LINE_DOWN ZERO_8_1 -.define SRC_OFFSET ZERO_5_5 -.define DST_GR1 ZERO_5_5 -.define CPT_FILL ZERO_5_4 +.define SRC_OFFSET ZERO_5_5 +.define DST_GR1 ZERO_5_5 +.define CPT_FILL ZERO_5_4 +.define TMP ZERO_9_10 Addr_GR1: ; 3 address blocks to fill GR1 (address -1), stored in reversed endianess. .word $4F04, $2704, $FF03 @@ -229,7 +231,7 @@ Addr_GR1: ; 3 address blocks to fill GR1 (address -1), stored in reversed endian ld_src: ; compute offset - stx ZERO_5_4 + stx TMP sty FAC1 lda #WIDTH_WORLD sta FAC2 @@ -237,7 +239,7 @@ ld_src: sta SRC_OFFSET+1 txa clc - adc ZERO_5_4 + adc TMP sta SRC_OFFSET lda SRC_OFFSET+1 adc #0 @@ -277,11 +279,22 @@ copy_8x2_lines: ; call 3 times to fill the screen ldy #DBG_DISP_WIDTH copy_2_lines: lda (SRC_LINE_DOWN),Y + cmp #eACTORTYPES::FIRST_DYNAMIC + bcc keep_color_1 + lda #$F ; white + keep_color_1: asl asl asl - asl - ora (SRC_LINE_UP),Y + asl + sta TMP + lda (SRC_LINE_UP),Y + cmp #eACTORTYPES::FIRST_DYNAMIC + bcc keep_color_2 + lda #$F ; white + keep_color_2: + and #$F + ora TMP sta (DST_GR1), Y dey bne copy_2_lines diff --git a/src/escape.cfg b/src/escape.cfg index 816d3db..b673f25 100644 --- a/src/escape.cfg +++ b/src/escape.cfg @@ -1,27 +1,29 @@ # Configuration: # APPLESOFT required -# HGR1 & HGR2 segment reserved +# HGR1 & HGR2 memory reserved +# CODE2, RODATA and DATA segment are loaded contiguously in the main memory +# but will be run from MAIN2 memory. The program has to do the relocation. FEATURES { - STARTADDRESS: default = $0800; + STARTADDRESS: default = $0803; } SYMBOLS { __EXEHDR__: type = import; + __FILETYPE__: type = weak, value = $0006; # ProDOS file type } MEMORY { - ZP: file = "", start = $0000, size = $00FF; - HEADER: file = %O, start = %S - 4, size = $0004; - MAIN: file = %O, define = yes, start = %S, size = $2000 - %S; - HGR: file = "", define = no, start = $2000, size = $4000; - CODE2: file = %O, define = yes, start = $6000, size = $100; - DATA: file = %O, define = yes, start = __CODE2_LAST__,size = $3000; - BSSMEM: file = "", define = no, start = __DATA_LAST__, size = $9600 - __DATA_LAST__; + ZP: file = "", start = $0000, size = $00FF; + HEADER: file = %O, start = %S - $3A, size = $003A; + HGR: file = "", define = yes, start = $2000, size = $4000; + MAIN2: file = "", define = yes, start = $6000, size = $3000; + BSSMEM: file = "", define = yes, start = __MAIN2_LAST__, size = $BF00 - __BSSMEM_START__; + MAIN: file = %O, define = yes, start = %S, size = __BSSMEM_START__ - %S - __HGR_SIZE__; } SEGMENTS { - ZEROPAGE: load = ZP, type = zp, optional = yes; - EXEHDR: load = HEADER, type = ro; - CODE: load = MAIN, type = rw; - CODE2: load = CODE2, type = rw, optional = yes; - RODATA: load = DATA, type = ro, optional = yes, align = $100; - DATA: load = DATA, type = rw, optional = yes, align = $100; - BSS: load = BSSMEM, type = bss, optional = yes, define = yes, align = $100; + ZEROPAGE: load = ZP, type = zp, optional = no; + EXEHDR: load = HEADER, type = ro; + CODE: load = MAIN, type = rw, define = yes; + CODE2: load = MAIN, run = MAIN2, type = rw, define = yes; + RODATA: load = MAIN, run = MAIN2, type = ro, define = yes, align = $100; + DATA: load = MAIN, run = MAIN2, type = rw, define = yes, align = $100; + BSS: load = BSSMEM, type = bss, define = yes, align = $100; } diff --git a/src/game_loop.asm b/src/game_loop.asm index af29d7c..2b6fb75 100644 --- a/src/game_loop.asm +++ b/src/game_loop.asm @@ -13,7 +13,7 @@ ; You should have received a copy of the GNU General Public License ; along with this program. If not, see . - +.include "actors/actors.inc" .include "world/level.inc" .include "world/world.inc" .include "display.inc" @@ -34,23 +34,32 @@ .import player_move_iny .import player_move_dex .import player_move_dey -.import Player_XY +.import ActorPositions ; world .import world_set_player +; actors +.import ActorPositions ; ************ .include "builder/builder.inc" .import world_init .import player_init .import view_init +.import Actors_Init ; ************ -.define KEY_UP $C9 -.define KEY_LEFT $CA -.define KEY_DOWN $CB -.define KEY_RIGHT $CC -.define TAB $89 +.define KEY_UP_UPP $C9 ; 'I' +.define KEY_UP_LOW $E9 ; 'i' +.define KEY_LEFT_UPP $CA ; 'J' +.define KEY_LEFT_LOW $EA ; 'j' +.define KEY_DOWN_UPP $CB ; 'K' +.define KEY_DOWN_LOW $EB ; 'k' +.define KEY_RIGHT_UPP $CC ; 'L' +.define KEY_RIGHT_LOW $EC ; 'l' +.define TAB $89 ; '\t' + +.define Player_XY ActorPositions + eACTORTYPES::PLAYER .CODE @@ -63,24 +72,21 @@ game_loop: jsr levels_init - - lda #0 - sta NextLevel + jsr Actors_Init level_loop: jsr level_enter ; Uses NextLevel as level number - ; ***************** - ; jsr Build_Level - jsr Display_Map_Init - ; ldx Rooms+2 ; Rooms[0].x - ; ldy Rooms+3 ; Rooms[0].y - ; jsr player_init + ; ***************** + jsr Display_Map_Init + + ldx Player_XY + ldy Player_XY + 1 jsr world_init + jsr view_init ; ***************** - ldx Player_XY ldy Player_XY+1 @@ -97,7 +103,7 @@ game_loop: jsr key_action lda ExitLevel - cmp TRUE + cmp #TRUE bne kbd_loop jsr level_exit @@ -108,16 +114,29 @@ game_loop: ; action on key pressed key_action: - cmp #KEY_UP + cmp #KEY_UP_UPP beq move_up - cmp #KEY_RIGHT + cmp #KEY_UP_LOW + beq move_up + + cmp #KEY_RIGHT_UPP beq move_right - cmp #KEY_DOWN + cmp #KEY_RIGHT_LOW + beq move_right + + cmp #KEY_DOWN_UPP beq move_down - cmp #KEY_LEFT + cmp #KEY_DOWN_LOW + beq move_down + + cmp #KEY_LEFT_UPP beq move_left + cmp #KEY_LEFT_LOW + beq move_left + cmp #TAB beq display_map + rts move_up: @@ -125,28 +144,24 @@ move_up: ldy Player_XY+1 dey jsr player_move - ; jsr player_move_dey jmp end_action_move move_right: ldx Player_XY ldy Player_XY+1 inx jsr player_move - ; jsr player_move_inx jmp end_action_move move_down: ldx Player_XY ldy Player_XY+1 iny jsr player_move - ; jsr player_move_iny jmp end_action_move move_left: ldx Player_XY ldy Player_XY+1 dex jsr player_move - ; jsr player_move_dex jmp end_action_move end_action_move: ; update player/view coordinates and refresh the display diff --git a/src/io/files.asm b/src/io/files.asm new file mode 100644 index 0000000..b243486 --- /dev/null +++ b/src/io/files.asm @@ -0,0 +1,481 @@ +; Copyright (C) 2021 Christophe Meneboeuf +; +; 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 . + + +; 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+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+1 + lda #1 + ldx #0 + jsr _Write + + lda Lvl_Nr + jsr _FindLevelLayout ; compute offset and sets file read position + + lda #ReadWriteBuffer + sta READ_DST+1 + lda #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+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+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+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+1 + lda #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+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+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+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+1 + lda #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+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+1 + lda #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 \ No newline at end of file diff --git a/src/io/files.inc b/src/io/files.inc new file mode 100644 index 0000000..caf1d18 --- /dev/null +++ b/src/io/files.inc @@ -0,0 +1,30 @@ +; Copyright (C) 2021 Christophe Meneboeuf +; +; 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 . + + +; 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 diff --git a/src/io/textio.asm b/src/io/textio.asm index daf19d4..f4d77ee 100644 --- a/src/io/textio.asm +++ b/src/io/textio.asm @@ -151,7 +151,7 @@ Cin_Str: sta TXT1_LINE23, X ; erase the cursor lda #0 sta CIN_STR, X - + rts delete: diff --git a/src/io/title.asm b/src/io/title.asm index f91c13a..e9a2c3a 100644 --- a/src/io/title.asm +++ b/src/io/title.asm @@ -35,17 +35,15 @@ GR_TITLE_09 : .byte $0,$0,$99,$0,$0,$0,$0,$0,$0,$0,$0,$0,$88,$0,$88,$0,$0,$0,$0 GR_TITLE_10 : .byte $0,$0,$99,$99,$99,$99,$99,$0,$88,$0,$0,$0,$88,$0,$88,$0,$0,$0,$0,$0,$88,$0,$0,$0,$0,$88,$0,$88,$0,$0,$0,$0,$0,$0,$99,$99,$99,$99,$99,$0 GR_TITLE_11 : .byte $0,$0,$99,$99,$99,$99,$99,$0,$88,$88,$88,$88,$0,$0,$0,$88,$88,$88,$88,$0,$88,$0,$0,$0,$0,$88,$0,$88,$0,$0,$0,$0,$0,$0,$99,$99,$99,$99,$99,$0 GR_TITLE_12 : .byte $0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0 -GR_TITLE_13 : .byte $0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0 -GR_TITLE_14 : .byte $0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0 -GR_TITLE_15 : .byte $0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$55,$55,$0,$0,$55,$55,$55,$0,$0,$55,$55,$0,$0,$0,$0,$55,$55,$55,$0,$55,$55,$55,$0,$55,$55,$0,$55,$55,$55,$0 -GR_TITLE_16 : .byte $0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$55,$0,$55,$0,$55,$0,$0,$0,$55,$0,$0,$0,$0,$0,$0,$0,$0,$55,$0,$55,$0,$55,$0,$0,$55,$0,$55,$0,$55,$0 -GR_TITLE_17 : .byte $0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$55,$55,$0,$0,$55,$0,$55,$0,$55,$0,$0,$0,$0,$0,$0,$55,$0,$0,$0,$55,$0,$55,$0,$0,$55,$0,$55,$55,$55,$0 -GR_TITLE_18 : .byte $0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$55,$0,$55,$0,$55,$55,$55,$0,$0,$55,$55,$0,$0,$0,$0,$55,$55,$55,$0,$55,$55,$55,$0,$0,$55,$0,$0,$0,$55,$0 +GR_TITLE_13 : .byte $0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0 +GR_TITLE_14 : .byte $0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$55,$55,$55,$55,$0,$0,$55,$55,$55,$55,$55,$55,$0,$55,$55,$55,$55,$55,$55,$0,$55,$55,$55,$55,$55,$0,$0,$0 +GR_TITLE_15 : .byte $0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$55,$0,$0,$0,$0,$55,$0,$0,$0,$0,$0,$0,$55,$0,$55,$0,$0,$0,$0,$0,$0,$55,$0,$0,$0,$0,$55,$0,$0 +GR_TITLE_16 : .byte $0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$55,$55,$55,$55,$55,$55,$0,$55,$55,$55,$55,$55,$55,$0,$55,$55,$55,$55,$0,$0,$0,$55,$55,$55,$55,$55,$0,$0,$0 +GR_TITLE_17 : .byte $0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$55,$0,$0,$0,$0,$55,$0,$55,$0,$0,$0,$0,$0,$0,$55,$0,$0,$0,$0,$0,$0,$55,$0,$0,$0,$0,$0,$0,$0 +GR_TITLE_18 : .byte $0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$55,$0,$0,$0,$0,$55,$0,$55,$55,$55,$55,$55,$55,$0,$55,$0,$0,$0,$0,$0,$0,$55,$0,$0,$0,$0,$0,$0,$0 GR_TITLE_19 : .byte $0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0,$0 -STR_NAME: ASCIIZ "WHAT'S YOUR NAME, ADVENTURER?" - .CODE @@ -102,9 +100,10 @@ Title_Scr_Addr: .word GR_TITLE_11, GR_TITLE_12, GR_TITLE_13, GR_TITLE_14, GR_TITLE_15, GR_TITLE_16, GR_TITLE_17, GR_TITLE_18, GR_TITLE_19 .CODE -; @brief Displays's the title screen +; @brief Displays's the title screen and main game menu Title: + ; Title Screen jsr Clear_Gr1 jsr ClearTxt @@ -133,11 +132,4 @@ Title: cpy #$26 bne loop_scrolling - - lda #>STR_NAME - ldx #__MAIN_LAST__ + lda #>__CODE2_LOAD__ sta FROM+1 - lda #<__CODE2_START__ + lda #<__CODE2_RUN__ sta TO - lda #>__CODE2_START__ + lda #>__CODE2_RUN__ sta TO+1 - lda #<(__CODE2_LAST__ - __CODE2_START__) + lda #<__CODE2_SIZE__ sta SIZEL - lda #>(__CODE2_LAST__ - __CODE2_START__) + lda #>__CODE2_SIZE__ sta SIZEH jsr memcpy - - ; Relocate DATA from its freshly loaded location to __DATA_START__ - ; computing DATA actual starting address - lda #<(__MAIN_LAST__ + __CODE2_LAST__ - __CODE2_START__) + ; relocating RODATA + lda #<__RODATA_LOAD__ sta FROM - lda #>(__MAIN_LAST__ + __CODE2_LAST__ - __CODE2_START__) + lda #>__RODATA_LOAD__ sta FROM+1 - lda #<__DATA_START__ + lda #<__RODATA_RUN__ sta TO - lda #>__DATA_START__ + lda #>__RODATA_RUN__ + sta TO+1 + lda #<__RODATA_SIZE__ + sta SIZEL + lda #>__RODATA_SIZE__ + sta SIZEH + jsr memcpy + ; relocating DATA + lda #<__DATA_LOAD__ + sta FROM + lda #>__DATA_LOAD__ + sta FROM+1 + lda #<__DATA_RUN__ + sta TO + lda #>__DATA_RUN__ sta TO+1 lda #<__DATA_SIZE__ sta SIZEL @@ -70,20 +104,71 @@ _main: sta SIZEH jsr memcpy - jsr Title ; will init the seed + jsr _StartMenu ; will init the seed ; overwrite the seed to debug - ;lda #$0 - ;sta SEED0 - ;lda #$0 - ;sta SEED1 - ;lda #$0 - ;sta SEED2 - ;lda #$0 - ;sta SEED3 + ; lda #$0 + ; sta SEED0 + ; lda #$0 + ; sta SEED1 + ; lda #$0 + ; sta SEED2 + ; lda #$0 + ; sta SEED3 + jsr Random8_Init ; Run jsr game_loop rts + + +; @brief Starting game menu +_StartMenu: + + ; Scrolling Title + jsr Title + + ; New game or continue + lda #>STR_NEWGAME + ldx #STR_JOURNEY + ldx #STR_NAME + ldx #. - -; Must be the same as in memory.inc !! -.define ZERO_2_1 $19 -.define ZERO_2_3 $1B -.define ZERO_8_1 $D6 -.define ZERO_8_2 $D7 -.define FROM ZERO_2_1 -.define TO ZERO_2_3 -.define SIZEH ZERO_8_1 -.define SIZEL ZERO_8_2 +.include "memory.inc" .export memcpy -.export TXT1_LINES +.export memset +.export meminit - -.DATA -TXT1_LINES: -.word $400, $480, $500, $580, $600, $680, $700, $780, $428, $4A8, $528, $5A8, $628, $6A8 -.word $728, $7A8, $450, $4D0, $550, $5D0, $650, $6D0, $750, $7D0 - .CODE ; http://www.6502.org/source/general/memory_move.html @@ -69,4 +55,84 @@ MU3: DEY DEC TO+1 DEX BNE MU1 - RTS \ No newline at end of file + 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 \ No newline at end of file diff --git a/src/memory.inc b/src/memory.inc index 1f7dbf3..cd64635 100644 --- a/src/memory.inc +++ b/src/memory.inc @@ -110,9 +110,8 @@ ; *********** CUSTOM ROUTINES ********* .define FROM ZERO_2_1 ; 2 bytes .define TO ZERO_2_3 ; 2 bytes -.define SIZEH ZERO_8_1 -.define SIZEL ZERO_8_2 -.import memcpy +.define SIZEH ZERO_8_2 +.define SIZEL ZERO_8_1 ; ************ MACROS *********** diff --git a/src/player.asm b/src/player.asm index 2e8e55f..4fd8053 100644 --- a/src/player.asm +++ b/src/player.asm @@ -20,6 +20,7 @@ .include "monitor.inc" .include "io/textio.inc" .include "world/world.inc" +.include "actors/actors.inc" ; init the player's structures @@ -34,39 +35,26 @@ ; They may be unmodified ;) ; DESTROY A, X, Y, ZERO_2_1, ZERO_2_2 -; Increments Player's X position -.export player_move_inx -; Increments Player's Y position -.export player_move_iny -; Decrements Player's X position -.export player_move_dex -; Decrements Player's Y position -.export player_move_dey - -; Player coordinates in the maze ([0:255], [0:255]) -.export Player_XY .import Compute_Maze_Addr .import Reactions_lsb .import Reactions_msb +.import ActorTypes +.import ActorPositions -.BSS +.define TO_BE_PATCHED 0 +.define Player_XY ActorPositions + eACTORTYPES::PLAYER -Player_XY: .res 2 +.DATA +STR_HIT_WALL: ASCIIZ "YOU HIT A WALL" .CODE -STR_GO_UP: ASCIIZ "YOU GO NORTH" -STR_GO_RIGHT: ASCIIZ "YOU GO EAST" -STR_GO_DOWN: ASCIIZ "YOU GO SOUTH" -STR_GO_LEFT: ASCIIZ "YOU GO WEST" -STR_HIT_WALL: ASCIIZ "YOU HIT A WALL" - ; @brief Player initial coords ; @param X player's x -; @param Y player's y +; @param Y player's y player_init: stx Player_XY sty Player_XY+1 @@ -80,26 +68,30 @@ player_init: player_move: stx NEW_PLAYER_XY - sty NEW_PLAYER_XY+1 + sty NEW_PLAYER_XY+1 jsr Compute_Maze_Addr - - ; get the actor + + ; get the actor id stx ADDR_IN_MAZE sta ADDR_IN_MAZE+1 ldy #0 lda (ADDR_IN_MAZE), Y tax - + + ; get the actor's type + lda ActorTypes, X + tay + ; get the reaction address - lda Reactions_lsb, X + lda Reactions_lsb, Y sta FUNC_REACTION + 1 - lda Reactions_msb, X + lda Reactions_msb, Y sta FUNC_REACTION+2 - FUNC_REACTION : jsr 0 + FUNC_REACTION : jsr TO_BE_PATCHED ; actord id in Y - cmp TRUE + cmp #TRUE bne end_player_move ldx NEW_PLAYER_XY stx Player_XY @@ -113,49 +105,6 @@ end_player_move: rts -; !!! ALL THE MOVE FUNCTION HAVE TO BE GROUPED TOGHETHER -; AS THERE IS A COMMON RETURN POINT TO WHICH THEY BRANHC (KEEP PC's DISTANCE < 127) !!! - -player_move_inx: - - ; test that x+1 is "WALKABLE" - ldx Player_XY - ldy Player_XY+1 - jsr Compute_Maze_Addr ; we get the adress for x,y then we increment x - stx ADDR_IN_MAZE - sta ADDR_IN_MAZE+1 - ldy #1 ; will look at x+1 - lda #ACTORS::WALKABLE - cmp (ADDR_IN_MAZE), Y - bcc hit_wall ; carry cleared if A is strictly the lesser --> not walkable - ldx Player_XY - inx - stx Player_XY ; walkable - PRINT STR_GO_RIGHT - jmp return_from_player_move - - - -player_move_dex: - - ; test that x-1 is "WALKABLE" - ldx Player_XY - dex - ldy Player_XY+1 - jsr Compute_Maze_Addr ; we get the adress for x-1 - stx ADDR_IN_MAZE - sta ADDR_IN_MAZE+1 - ldy #0 ; will look at x-1 - lda #ACTORS::WALKABLE - cmp (ADDR_IN_MAZE), Y - bcc hit_wall ; carry cleared if A is strictly the lesser --> not walkable - ldx Player_XY - dex - stx Player_XY ; walkable - PRINT STR_GO_LEFT - jmp return_from_player_move - - ; Common code to return from the moves. ; Moves BRANCH to here return_from_player_move: @@ -169,47 +118,3 @@ hit_wall: PRINT STR_HIT_WALL jmp return_from_player_move - -player_move_iny: - - ; test that y+1 is "WALKABLE" - ldy Player_XY+1 - ldx Player_XY - iny - jsr Compute_Maze_Addr ; we get the adress for x,y+1 - stx ADDR_IN_MAZE - sta ADDR_IN_MAZE+1 - ldy #0 - lda #ACTORS::WALKABLE - cmp (ADDR_IN_MAZE), Y - bcc hit_wall ; carry cleared if A is strictly the lesser --> not walkable - - ldy Player_XY+1 ; walkable - iny - sty Player_XY+1 - PRINT STR_GO_DOWN - jmp return_from_player_move - - -player_move_dey: - - ; test that y-1 is "WALKABLE" - ldy Player_XY+1 - ldx Player_XY - dey - jsr Compute_Maze_Addr ; we get the adress for x,y-1 - stx ADDR_IN_MAZE - sta ADDR_IN_MAZE+1 - ldy #0 - lda #ACTORS::WALKABLE - cmp (ADDR_IN_MAZE), Y - bcc hit_wall ; carry cleared if A is strictly the lesser --> not walkable - - ldy Player_XY+1 ; walkable - dey - sty Player_XY+1 - PRINT STR_GO_UP - bvc return_from_player_move - - - .undef ADDR_IN_MAZE diff --git a/src/tiles.asm b/src/tiles.asm index 31e7298..8011e8a 100644 --- a/src/tiles.asm +++ b/src/tiles.asm @@ -106,10 +106,10 @@ FLOOR_4: .byte $D5, $AA, $D5, $AA STAIR_DOWN: .byte $55, $2A, $55, $2A -.byte $01, $AA, $D4, $00 -.byte $01, $8A, $D4, $82 -.byte $71, $01, $C0, $82 -.byte $71, $79, $00, $00 +.byte $11, $00, $40, $00 +.byte $71, $7F, $7F, $1F +.byte $71, $01, $C5, $82 +.byte $71, $79, $80, $8A .byte $71, $79, $3C, $00 .byte $71, $79, $3C, $1E .byte $71, $79, $3C, $1E @@ -123,21 +123,21 @@ STAIR_DOWN: .byte $01, $8A, $95, $A8 STAIR_UP: .byte $55, $2A, $55, $2A -.byte $71, $7F, $7F, $1F -.byte $71, $79, $D4, $82 -.byte $71, $79, $3C, $8A -.byte $71, $79, $3C, $88 -.byte $71, $79, $3C, $1E -.byte $71, $79, $3C, $1E -.byte $71, $79, $3C, $1E -.byte $71, $79, $3C, $1E -.byte $71, $79, $3C, $1E -.byte $70, $79, $3C, $1E -.byte $70, $79, $3C, $1E -.byte $70, $79, $3C, $1E -.byte $90, $78, $3C, $1E -.byte $D0, $A8, $3C, $1E -.byte $D0, $A0, $94, $1E +.byte $01, $00, $90, $F8 +.byte $01, $AA, $70, $79 +.byte $01, $E2, $73, $79 +.byte $01, $60, $73, $79 +.byte $41, $67, $73, $79 +.byte $41, $67, $73, $79 +.byte $41, $67, $73, $79 +.byte $41, $67, $73, $79 +.byte $41, $67, $73, $79 +.byte $40, $67, $73, $79 +.byte $40, $67, $73, $79 +.byte $40, $67, $73, $79 +.byte $40, $67, $F3, $A1 +.byte $40, $67, $D3, $A8 +.byte $C0, $A7, $91, $A8 WALL_1: .byte 197, 138, 213, 168 .byte 197, 138, 213, 168 @@ -172,6 +172,74 @@ WALL_2: .byte $7F, $7F, $7F, $7F .byte $7F, $7F, $7F, $7F .byte $7F, $7F, $7F, $7F +COFFER: +.byte $55, $2A, $55, $2A +.byte $01, $20, $00, $00 +.byte $01, $7E, $0F, $00 +.byte $41, $67, $3C, $00 +.byte $31, $66, $4C, $01 +.byte $31, $66, $4C, $01 +.byte $31, $66, $4C, $01 +.byte $71, $7F, $7F, $01 +.byte $31, $C0, $40, $01 +.byte $35, $C0, $40, $2B +.byte $B0, $C0, $40, $01 +.byte $30, $00, $40, $01 +.byte $30, $00, $40, $01 +.byte $70, $7F, $7F, $01 +.byte $70, $7F, $7F, $01 +.byte $10, $00, $40, $00 +RAT: +.byte $55, $2A, $55, $2A +.byte $01, $20, $03, $00 +.byte $01, $20, $EF, $81 +.byte $01, $20, $7C, $1F +.byte $01, $78, $7F, $1F +.byte $01, $7E, $BF, $85 +.byte $41, $7F, $0F, $00 +.byte $71, $7F, $03, $00 +.byte $7D, $7F, $03, $00 +.byte $5D, $7F, $57, $2A +.byte $5C, $1F, $43, $00 +.byte $5C, $01, $43, $00 +.byte $50, $01, $4F, $00 +.byte $50, $1F, $40, $00 +.byte $10, $00, $40, $00 +.byte $10, $00, $40, $00 +SERPENT: +.byte $55, $2A, $55, $2A +.byte $01, $20, $03, $00 +.byte $01, $60, $0C, $00 +.byte $01, $60, $3F, $00 +.byte $01, $60, $8B, $80 +.byte $01, $60, $A3, $81 +.byte $01, $60, $00, $00 +.byte $01, $78, $00, $00 +.byte $01, $7E, $00, $00 +.byte $55, $2F, $55, $2A +.byte $70, $01, $40, $00 +.byte $30, $18, $40, $00 +.byte $30, $78, $40, $00 +.byte $30, $60, $40, $00 +.byte $70, $79, $40, $00 +.byte $40, $1F, $40, $00 +SPIDER: +.byte $55, $2A, $55, $2A +.byte $01, $18, $03, $00 +.byte $01, $60, $00, $00 +.byte $01, $78, $03, $00 +.byte $01, $78, $03, $00 +.byte $01, $60, $00, $00 +.byte $01, $78, $03, $00 +.byte $71, $5F, $7F, $01 +.byte $01, $5E, $0F, $00 +.byte $75, $5F, $7F, $2B +.byte $10, $56, $0E, $00 +.byte $70, $5F, $7F, $01 +.byte $10, $58, $43, $00 +.byte $50, $7F, $7F, $00 +.byte $10, $60, $40, $00 +.byte $10, $00, $40, $00 UNKNOWN: .byte $80, $80, $80, $80 .byte $80, $80, $80, $80 @@ -192,8 +260,34 @@ UNKNOWN: .ALIGN 256 -; DON"T FORGET TO UPDATE NB_TILES!! + +; Tiles used by ACTORS +; 128 addresses TILES: .word PLAYER -.word FLOOR_1, FLOOR_2, FLOOR_3, FLOOR_4, FLOOR_4, FLOOR_4, STAIR_DOWN, STAIR_UP -.word WALL_1, WALL_2, UNKNOWN +; floors +.word FLOOR_1, FLOOR_2, FLOOR_3, FLOOR_4, FLOOR_4, FLOOR_4 +; walls +.word WALL_1, WALL_2, WALL_2, WALL_2 +; stairs +.word STAIR_DOWN, STAIR_UP +; items +.word COFFER +; monsters +.word RAT, SPIDER, SERPENT +; other +; COMPLETE TO GET THE 128 TILES!!! +.word UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN +.word UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN +.word UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN +.word UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN +.word UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN +.word UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN +.word UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN +.word UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN +.word UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN +.word UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN +.word UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN +.word UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN +.word UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN +.word UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN, UNKNOWN diff --git a/src/world.asm b/src/world.asm deleted file mode 100644 index 7af4cfa..0000000 --- a/src/world.asm +++ /dev/null @@ -1,154 +0,0 @@ - -; Copyright (C) 2018 Christophe Meneboeuf -; -; 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 . - - -.include "world.inc" -.include "tiles.inc" -.include "random.inc" -.include "math.inc" -.include "memory.inc" - - - -.export World - -; initializes the world -; DESTROYS A,X,Y, ZERO_2_1, ZERO_2_2, ZERO_2_3 -.export world_init - -; sets the player's position onto the Maze -; in: X = x coord in the maze -; in: Y = y coord in the maze -; out : X and Y as they where given -; DESTROYS A,X,Y, ZERO_2_1, ZERO_2_2, ZERO_2_4, ZERO_2_5 -.export world_set_player - -; Computes the adress corresponding to the coordinates in the maze -; in: X = x coord in the maze -; in: Y = y coord in the maze -; out: AX = Address corresponding to (x,y) in the World array -; DESTROYS A,X,Y, ZERO_2_1, ZERO_2_2, ZERO_2_3 -.export Compute_Maze_Addr - - -.define TILE_NR ZERO_2_1 -.define COORD_X ZERO_2_1 -.define COORD_Y ZERO_2_2 -.define OFFSET ZERO_2_2 - - -.BSS - -; The tile where the player stands -.struct Tile_player_standing - addr .word ; adress of the location - actor .byte ; actor on the location tile -.endstruct - -.CODE - -; @param X Player's x -; @param Y Player's y -world_init: - ; Saving the first tile on which the player stands - ; FIXME player could be standing anywhere on any type of floor - jsr Compute_Maze_Addr - stx Tile_player_standing::addr - sta Tile_player_standing::addr+1 - stx ZERO_2_1 - sta ZERO_2_1+1 - ldy #0 - lda (ZERO_2_1), Y - sta Tile_player_standing::actor - - rts - - -; sets the player's position onto the World -world_set_player: - - stx ZERO_2_4 - sty ZERO_2_5 - - ; restore the previous tile - ldx Tile_player_standing::addr - lda Tile_player_standing::addr+1 - stx ZERO_2_1 - sta ZERO_2_1+1 - ldy #0 - lda Tile_player_standing::actor - sta (ZERO_2_1), Y - - ; save the next tile - ldx ZERO_2_4 - ldy ZERO_2_5 - jsr Compute_Maze_Addr ; get's player's position address in memory - stx Tile_player_standing::addr - sta Tile_player_standing::addr+1 - stx ZERO_2_1 - sta ZERO_2_1+1 - ldy #0 - lda (ZERO_2_1), y - sta Tile_player_standing::actor - - ; sets the player on the tile - lda #ACTORS::PLAYER - sta (ZERO_2_1), y - - ; restore the given locations - ldx ZERO_2_4 - ldy ZERO_2_5 - - rts - -; Destroys ZERO_2_1, ZERO_2_2, ZERO_2_3 ZERO_7_1 and ZERO_7_2 -Compute_Maze_Addr: - - stx COORD_X - - ; offset due to Y coord - sty FAC1 - lda #WIDTH_WORLD - sta FAC2 - jsr mul8 - tay ; high part of the mul - txa ; low part of the mul - - ; adding offset due to X - clc - adc COORD_X - sta OFFSET - tya - adc #0 - sta OFFSET+1 - - ; adding the offset to the address - lda #World - adc OFFSET+1 ; high part of address to be returned in A - - rts - - - -.DATA - -.align 256 - -World: .res (WIDTH_WORLD) * (HEIGHT_WORLD) diff --git a/src/world.inc b/src/world.inc deleted file mode 100644 index 289d15a..0000000 --- a/src/world.inc +++ /dev/null @@ -1,34 +0,0 @@ -; The world contains a Maze, filled with Actors -; Actors can be static, such a a floor or a wall, -; dynamic such as a door -; or alive, such as a monster - - -.define MAXIMUM_WIDTH_MAZE 64 ; must be a power of 2 -.define MAXIMUM_HEIGHT_MAZE 64 ; must be a power of 2 -.define WIDTH_WORLD 64 -.define NEG_WIDTH_WORLD $C0 -.define HEIGHT_WORLD 64 -.define NEG_HEIGHT_WORLD 64 $C0 - - -.enum ACTORS - - PLAYER = 0 - - FLOOR_1 = 1 - FLOOR_2 ; FLOOR BY DEFAULT - FLOOR_3 - FLOOR_4 - WALKABLE = FLOOR_4 ; Player won't be allowed to go on anything > WALKABLE - - NOT_WALKABLE - NOT_TRANSPARENT = NOT_WALKABLE - WALL_1 = NOT_WALKABLE - WALL_2 - - UNKNOWN - - NB_ACTORS - -.endenum diff --git a/src/world/level.asm b/src/world/level.asm index 944fc20..d923a5b 100644 --- a/src/world/level.asm +++ b/src/world/level.asm @@ -17,133 +17,119 @@ .include "../common.inc" .include "../memory.inc" .include "../random.inc" -.include "../builder/actors.inc" +.include "../math.inc" +.include "../actors/actors.inc" .include "../builder/builder.inc" +.include "../io/files.inc" .include "level_private.inc" ; code .export levels_init .export level_enter .export level_exit +.export level_get_config_offset +.export level_reset_states ; data -.export Levels +.export LevelConfigs +.export NbLevels .export CurrentLevel .export NextLevel .export ExitLevel +.export LevelIsBuilt .import player_init +.import ActorsInLevel +.import ActorPositions +.import World .BSS CurrentLevel: .res 1 +NbLevels: .res 1 NextLevel: .res 1 ExitLevel: .res 1 - -.align 256 ; to be sure it is accessible with an offset -Levels: .res SIZEOF_CONF_LEVEL * NB_LEVELS +LevelIsBuilt: .res 1 - -.CODE +LevelConfigs: .res 1 + NB_LEVELS * SIZEOF_CONF_LEVEL -.define NR_ACTORS ZERO_4_1 -.define NR_LEVELS ZERO_4_2 -; TODO Load a configuration file from disk! +.segment "CODE2" + + +.define ACCUMULATOR ZERO_9_4 ; 2 bytes + +; @param LevelNr in X +_Set_Params_LoadSaveLevelActors: + + ; compute offset in file + lda #0 + sta ACCUMULATOR + sta ACCUMULATOR+1 + beq end_loop_offset +loop_offset: ; accumulating offsets + clc + lda ACCUMULATOR + adc #<(SIZEOF_ACTORS_T) + sta ACCUMULATOR + lda ACCUMULATOR+1 + adc #>(SIZEOF_ACTORS_T) + sta ACCUMULATOR+1 + dex + bne loop_offset +end_loop_offset: + ; set function parameters + sta Param_FileOffset+3 + lda ACCUMULATOR + sta Param_FileOffset+2 + lda #Str_FileLevelsActors + sta Param_FileOpen+2 + lda #ActorsInLevel + sta Param_FilesReadWrite+3 + + rts + + +.define NR_LEVELS ZERO_4_1 levels_init: - ldx #0 - ldy #0 - lda #NB_LEVELS + ; file path + lda #Str_FileLevelConfs + sta Param_FileOpen+2 + ; read buffer + lda #0 + sta Param_FileOffset+2 + sta Param_FileOffset+3 + sta Param_FileOffset+4 + lda #LevelConfigs + sta Param_FilesReadWrite+3 + lda #<(1 + SIZEOF_CONF_LEVEL * NB_LEVELS) + sta Param_FilesReadWrite+4 + lda #>(1 + SIZEOF_CONF_LEVEL * NB_LEVELS) + sta Param_FilesReadWrite+5 + + ; load + jsr ReadFile + + ; exploit + lda LevelConfigs + sta NbLevels sta NR_LEVELS + inc NR_LEVELS -level_conf_default: - ; level_nr - tya - iny - sta Levels, X - ; is_built - lda FALSE - sta Levels+1, x - ; seed - lda #0 - sta Levels+2, X - sta Levels+3, X - sta Levels+4, X - sta Levels+5, X - ; size - ; pos_player_enter - lda #$FF - sta Levels+7, X - sta Levels+8, X - ; actors - txa - clc - adc #9 - tax - lda #eACTORSREACTIVE::AA_NB - sta NR_ACTORS - lda #0 - - level_conf_actors: - sta Levels, X - inx - dec NR_ACTORS - bne level_conf_actors - - dec NR_LEVELS - bne level_conf_default - - ; level #0 - ldx #0 - lda #1 - sta Levels + 9 + eACTORSREACTIVE::AA_STAIRUP, X - lda #LEVELSIZE::TINY - sta Levels+6, X ; size - ; level #1 - clc - txa - adc #SIZEOF_CONF_LEVEL - tax - lda #1 - sta Levels + 9 + eACTORSREACTIVE::AA_STAIRUP, X - sta Levels + 9 + eACTORSREACTIVE::AA_STAIRDOWN, X - lda #LEVELSIZE::SMALL - sta Levels+6, X ; size - ; level #2 - clc - txa - adc #SIZEOF_CONF_LEVEL - tax - lda #1 - sta Levels + 9 + eACTORSREACTIVE::AA_STAIRUP, X - sta Levels + 9 + eACTORSREACTIVE::AA_STAIRDOWN, X - lda #LEVELSIZE::NORMAL - sta Levels+6, X ; size - ; level #3 - clc - txa - adc #SIZEOF_CONF_LEVEL - tax - lda #1 - sta Levels + 9 + eACTORSREACTIVE::AA_STAIRUP, X - sta Levels + 9 + eACTORSREACTIVE::AA_STAIRDOWN, X - lda #LEVELSIZE::BIG - sta Levels+6, X ; size - ; level #4 - clc - txa - adc #SIZEOF_CONF_LEVEL - tax - lda #1 - sta Levels + 9 + eACTORSREACTIVE::AA_STAIRDOWN, X - lda #LEVELSIZE::HUGE - sta Levels+6, X ; size - - ; global vars +; global vars lda #0 sta CurrentLevel - lda FALSE + sta NextLevel + lda #FALSE sta ExitLevel rts @@ -151,85 +137,51 @@ level_conf_default: ; @param: Uses NextLevel as level number -.define LEVEL_CONF_OFFSET ZERO_3 +.define LEVEL_STATE_OFFSET ZERO_9_1 +.define ADDR_LEVEL_CONF ZERO_9_2 ; 2 bytes level_enter: - ; debug: - ; lda NextLevel - ; cmp #0 - ; bne debug_end - ; jsr Random8 - ; debug_end: + lda NextLevel + jsr LoadState - jsr Random8_SaveRandomness + lda LevelIsBuilt + cmp #TRUE + beq level_was_built - ; get the level conf - lda #0 - ldx #0 - clc - get_level_conf: - tay - lda Levels, X - cmp NextLevel - beq end_idx_level - tya - adc #SIZEOF_CONF_LEVEL +level_generation: + + ; compute offset to level config + lda NextLevel + jsr level_get_config_offset + pha + clc + txa + adc #LevelConfigs + sta ADDR_LEVEL_CONF+1 + + ; init maze size + ldy #1 + lda (ADDR_LEVEL_CONF), Y ; size tax - bcc get_level_conf - end_idx_level: - stx LEVEL_CONF_OFFSET + tay + jsr Init_Dimensions_Maze - ; init seed for the level if not already built - lda Levels+1, X ; is_built - cmp FALSE - bne end_init_seed + ; player position returned in X and Y + jsr Build_Level + jsr player_init ; param: player pos in X and Y - jsr Random8 - ldx LEVEL_CONF_OFFSET - sta Levels+2, X ; seed[0] - jsr Random8 - ldx LEVEL_CONF_OFFSET - sta Levels+3, X ; seed[1] - jsr Random8 - ldx LEVEL_CONF_OFFSET - sta Levels+4, X ; seed[2] - jsr Random8 - ldx LEVEL_CONF_OFFSET - sta Levels+5, X ; seed[3] -end_init_seed: +level_was_built: - ; init the randomness with the values for the level - lda Levels+2, X ; seed[0] - sta SEED0 - lda Levels+3, X ; seed[1] - sta SEED1 - lda Levels+4, X ; seed[2] - sta SEED2 - lda Levels+5, X ; seed[3] - sta SEED3 - jsr Random8_Init - - ; init maze size - ldx LEVEL_CONF_OFFSET - txa - pha ; save LEVEL_CONF_OFFSET as its ZP will be overwritten - lda Levels+6, X ; size - tax - tay - jsr Init_Dimensions_Maze + ldx ActorPositions + eACTORTYPES::PLAYER + ldy ActorPositions + eACTORTYPES::PLAYER + 1 + jsr player_init - ; player position returned in X and Y - jsr Build_Level - jsr player_init ; param: player pos in X and Y +level_enter_end: - jsr Random8_RestoreRandomness - - pla ; restore LEVEL_CONF_OFFSET - tax - lda TRUE - sta Levels+1, X; is_built - - lda FALSE + lda #FALSE sta ExitLevel lda NextLevel @@ -238,28 +190,39 @@ end_init_seed: rts -.import Player_XY +.define Player_XY ActorPositions + eACTORTYPES::PLAYER level_exit: - ; get the level conf - lda #0 - ldx #0 - clc - get_level_conf_2: - tay - lda Levels, X - cmp CurrentLevel - beq end_idx_level_2 - tya - adc #SIZEOF_CONF_LEVEL - tax - bcc get_level_conf_2 - end_idx_level_2: - - ; save player pos in conf - lda Player_XY - sta Levels+7, X - lda Player_XY + 1 - sta Levels+8, X + lda CurrentLevel + jsr SaveState + + rts + +; @param Level_Nr in A +; @return Config offset for the level in X +level_get_config_offset: + + sta FAC1 + ldx #SIZEOF_CONF_LEVEL + stx FAC2 + jsr mul8 + ; first byte of conf is the number of levels + pha + clc + txa + adc #1 + tax + pla + adc #0 + + rts + +; @brief reset the states of all levels +level_reset_states: + + lda #0 + sta CurrentLevel + lda #NB_LEVELS + jsr ResetIsBuilt rts diff --git a/src/world/level.inc b/src/world/level.inc index c12a5f5..bfac7e7 100644 --- a/src/world/level.inc +++ b/src/world/level.inc @@ -14,14 +14,42 @@ ; along with this program. If not, see . -.include "level_private.inc" .import levels_init .import level_enter ; param: A = level_nr .import level_exit +.import level_get_config_offset .import CurrentLevel .import NextLevel .import ExitLevel -.import Levels +.import LevelConfigs +.import NbLevels + +.enum LEVELSIZE + TINY = 20 + SMALL = 24 + NORMAL = 32 + BIG = 48 + HUGE = 64 +.endenum + + +; struct Level +; { +; uint8_t is_built; +; uint8_t seed[4]; //< seed used to build the level +; coords_t pos_player_enter; //< position of player when entering the level (x,y) +; } +; + +; nb_levels >>>> ALWAYS OFFSET + 1!!! <<<< +; array [ + ; struct LevelsConf + ; { + ; uint8_t level_nr; + ; uint8_t size; //< eLEVELSIZE + ; uint8_t actors[NB_ACTORS_MAX]; //< number of actors of each kind added in the level after building the maze + ; } +; ] diff --git a/src/world/level_private.inc b/src/world/level_private.inc index 7642e2e..7671073 100644 --- a/src/world/level_private.inc +++ b/src/world/level_private.inc @@ -15,28 +15,11 @@ +; BEWARE: NB_LEVELS * SIZEOF_STATE_LEVEL shall not be > 256 +.define SIZEOF_STATE_LEVEL 7 + +.define SIZEOF_CONF_LEVEL 130 ;( NB_ACTORS_MAX + 2 ) +.define NB_LEVELS 3 -; typedef struct -; { -; uint8_t level_nr; -; uint8_t is_built; -; uint8_t seed[4]; //< seed used to build the level -; uint8_t size; //< eLEVELSIZE -; coords_t pos_player_enter; //< position of player when entering the level (x,y) -; uint8_t actors[AA_NB]; //< number of reactive actors of each kind in the level -; } -; level_conf_t; - -; BEWARE: NB_LEVELS * SIZEOF_CONF_LEVEL shall not be > 256 -.define SIZEOF_CONF_LEVEL 12 -.define NB_LEVELS 5 - -.enum LEVELSIZE - TINY = 20 - SMALL = 24 - NORMAL = 32 - BIG = 48 - HUGE = 64 -.endenum diff --git a/src/world/world.asm b/src/world/world.asm index 5a6f206..e942103 100644 --- a/src/world/world.asm +++ b/src/world/world.asm @@ -16,13 +16,14 @@ .include "world.inc" +.include "../common.inc" +.include "../actors/actors.inc" .include "../tiles.inc" .include "../random.inc" .include "../math.inc" .include "../memory.inc" - .export World ; initializes the world @@ -43,8 +44,11 @@ ; DESTROYS A,X,Y, ZERO_2_1, ZERO_2_2, ZERO_2_3 .export Compute_Maze_Addr +; #TRUE if an object has been picked by the player +.export World_PickedObject + +.export Tile_player_standing_actor -.define TILE_NR ZERO_2_1 .define COORD_X ZERO_2_1 .define COORD_Y ZERO_2_2 .define OFFSET ZERO_2_2 @@ -53,10 +57,13 @@ .BSS ; The tile where the player stands -.struct Tile_player_standing - addr .word ; adress of the location - actor .byte ; actor on the location tile -.endstruct +; The two memory locations must be adjacent +Tile_player_standing_addr: .res 2 +Tile_player_standing_actor: .res 1 + +.DATA + +World_PickedObject: .byte 0 .CODE @@ -66,51 +73,65 @@ world_init: ; Saving the first tile on which the player stands ; FIXME player could be standing anywhere on any type of floor jsr Compute_Maze_Addr - stx Tile_player_standing::addr - sta Tile_player_standing::addr+1 - stx ZERO_2_1 - sta ZERO_2_1+1 - ldy #0 - lda (ZERO_2_1), Y - sta Tile_player_standing::actor + stx Tile_player_standing_addr + sta Tile_player_standing_addr+1 + lda Tile_player_standing_actor + cmp #UNDEF + bne world_init_end + lda #eACTORTYPES::FLOOR_2 + sta Tile_player_standing_actor + +world_init_end: rts ; sets the player's position onto the World +.define PLAYER_XY ZERO_2_1; 2 bytes +.define NEXT_TILE_XY ZERO_2_4 ; 2 bytes world_set_player: - stx ZERO_2_4 - sty ZERO_2_5 + stx NEXT_TILE_XY + sty NEXT_TILE_XY+1 - ; restore the previous tile - ldx Tile_player_standing::addr - lda Tile_player_standing::addr+1 - stx ZERO_2_1 - sta ZERO_2_1+1 + ; restore the previous tile + ldx Tile_player_standing_addr + lda Tile_player_standing_addr+1 + stx PLAYER_XY + sta PLAYER_XY+1 ldy #0 - lda Tile_player_standing::actor - sta (ZERO_2_1), Y - + lda Tile_player_standing_actor + sta (PLAYER_XY), Y + ; save the next tile - ldx ZERO_2_4 - ldy ZERO_2_5 + ldx NEXT_TILE_XY + ldy NEXT_TILE_XY+1 jsr Compute_Maze_Addr ; get's player's position address in memory - stx Tile_player_standing::addr - sta Tile_player_standing::addr+1 - stx ZERO_2_1 - sta ZERO_2_1+1 + stx Tile_player_standing_addr + sta Tile_player_standing_addr+1 + stx PLAYER_XY + sta PLAYER_XY+1 ldy #0 - lda (ZERO_2_1), y - sta Tile_player_standing::actor + lda (PLAYER_XY), y + sta Tile_player_standing_actor + ; if an object was picked + ; override to force save a floor tile + lda World_PickedObject + cmp #TRUE + bne no_object_picked + lda #eACTORTYPES::FLOOR_2 + sta Tile_player_standing_actor + lda #FALSE + sta World_PickedObject + no_object_picked: ; sets the player on the tile - lda #ACTORS::PLAYER - sta (ZERO_2_1), y + lda #eACTORTYPES::PLAYER + sta (PLAYER_XY), y ; restore the given locations - ldx ZERO_2_4 - ldy ZERO_2_5 + ldx NEXT_TILE_XY + ldy NEXT_TILE_XY+1 rts @@ -147,7 +168,7 @@ Compute_Maze_Addr: -.DATA +.BSS .align 256 diff --git a/src/world/world.inc b/src/world/world.inc index 4ce1f1d..4bae3e9 100644 --- a/src/world/world.inc +++ b/src/world/world.inc @@ -27,31 +27,5 @@ .define WIDTH_WORLD 64 .define NEG_WIDTH_WORLD $C0 .define HEIGHT_WORLD 64 -.define NEG_HEIGHT_WORLD 64 $C0 +.define NEG_HEIGHT_WORLD $C0 - -.enum ACTORS - - PLAYER = 0 - - FLOOR_1 = 1 - FLOOR_2 ; FLOOR BY DEFAULT - FLOOR_3 - FLOOR_4 - FLOOR_5 - FLOOR_6 - STAIR_DOWN - STAIR_UP - WALKABLE = STAIR_UP ; Player won't be allowed to go on anything > WALKABLE - - NOT_TRANSPARENT = STAIR_UP - NOT_WALKABLE - - WALL_1 = NOT_WALKABLE - WALL_2 - - UNKNOWN - - NB_ACTORS - -.endenum