aboutsummaryrefslogtreecommitdiff
path: root/README.md
diff options
context:
space:
mode:
authorJuan J. Martinez <jjm@usebox.net>2023-11-05 11:22:55 +0000
committerJuan J. Martinez <jjm@usebox.net>2023-11-05 11:31:28 +0000
commit2fbdf974338bde8576efdae40a819a76b2391033 (patch)
tree64d41a37470143f142344f9a439d96de3e7918c2 /README.md
downloadkitsunes-curse-2fbdf974338bde8576efdae40a819a76b2391033.tar.gz
kitsunes-curse-2fbdf974338bde8576efdae40a819a76b2391033.zip
Initial import of the open source release
Diffstat (limited to 'README.md')
-rw-r--r--README.md152
1 files changed, 152 insertions, 0 deletions
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..4ab5cc9
--- /dev/null
+++ b/README.md
@@ -0,0 +1,152 @@
+# Kitsune's Curse
+
+This is an original game by [Juan J. Martinez](https://www.usebox.net/jjm/about/me/)
+for the Amstrad CPC 464 or compatible.
+
+Get the official releases from [Kitsune's Curse](https://www.usebox.net/jjm/kitsunes-curse/).
+
+**The game is finished, no further development is planned. The code has been open
+sourced in case the community finds it useful and helps making new games!**
+
+## Requirements
+
+ * A POSIX environment (Linux is perfect, Debian recommended)
+ * gcc (C & C++), GNU make, cmake, Python 3
+ * SDCC 4.0; later version may not work as SDCC changed the calling convention!
+
+## Building
+
+Run `make`.
+
+After a successful build, it should end with something like:
+
+```
+chksize 2816 ../build/main.map
+***
+ Max: 46080 bytes
+ Current: 42774 bytes (490 bytes left)
+***
+```
+
+To build and run on an emulator `make cpcec` (there are other targets).
+
+### Other targets
+
+ * `make clean` to remove output of compilation and generated files
+ * `make cleanall` to also remove the compiled tools
+
+## Technical details
+
+This game uses an engine that tracks dirty tiles and minimises the amount of
+drawing on the screen. It is essentially the same engine used in "The Dawn of
+Kernel". See "Mini-buffer engine" for further info.
+
+Memory Map:
+
+| Address | Content |
+| --- | --- |
+| `0x0100` | mini-buffers |
+| `0x0b00` | Game's code / ROM |
+| `0xa2fd` | Game's data / RAM |
+| `0xb215` | Stack limit |
+| `0xc000` | Video memory |
+
+(game's data and the stack limit may not be exact, see `build/main.map` for
+details once the game is built)
+
+### Mini-buffer engine
+
+The game uses "mini-buffers" to build the scene based on dirty tiles.
+
+Instead of tracking the areas of the screen that need redrawing between frames
+using a big buffer, when a part of the screen needs redrawing, a small buffer
+is allocated and background and masked sprites are drawn to it. When the scene
+is finished, those mini-buffers are copied to the screen in a fast loop.
+
+This reduces the memory requirements considerably, with some impact in the
+performance derived of the mini-buffer management. It can be a good engine
+for mid-size games targeting 64K that don't require a large amount of sprites
+on screen (this game supports up to 10 sprites of 8 * 24 pixels).
+
+The memory area dedicated to the mini-buffers is calculated with this formula:
+
+```
+(TW * TH / 2) * (SPRITE_TH * 2 + 2) * MAX_SPRITES
+```
+
+* TW: tile width in bytes (pixels / 2).
+* TH: tile width in pixels.
+* SPRITES_TH: sprites height in tiles (of TH pixels).
+* MAX_SPRITES: maximum number of sprites we may need to draw.
+
+In "Kitsune's Curse" this is `2560` bytes (placed on `0x0100` before the game's
+code), which is very little memory (e.g. a back buffer by hardware would
+require `16384` bytes).
+
+The dirty tiles are tracked with a tile map of the size of the playable screen
+(TMW * TMH; which is 20 * 20 or 160x160 pixels). Each entry on the map has a
+mini-buffer address that must be under `0x8000` because the most significant
+bit on the address is used as dirty flag, a pointer to the background tile, and
+the screen address where it should be drawn.
+
+Then there are functions to manipulate the tile map, and those functions either
+validate (no need to draw) or invalidate tiles (the tiles are "dirty" and need
+to be drawn on the screen).
+
+The tile map is drawn on screen with a call to update screen. At this point,
+all the mini-buffers are freed and available to start drawing the next frame.
+
+This game updates at 16.6 FPS, so there are 3 full frames to deal with game
+logic update, prepare mini-buffers, and update the screen.
+
+### Useful flags
+
+There are some defines to help troubleshoot issues:
+
+* `DEBUG`: show some debug information on screen (e.g. player checkpoints).
+* `SPRITE_DEBUG`: will use tile 14 to erase backgrounds providing a visual cue
+ of how the erase is behaving.
+* `FENCE_DEBUG`: keep count of the used mini-buffers and boundaries when
+ accessing several functions. On error, the screen border will change color
+ (e.g. 0x4b when getting a tile off-bounds, 0x58 when run out of mini-buffers,
+ etc), see `splib.c` for details.
+
+### Map structure
+
+The game has 60 screens, using `7682` bytes (`128.03` bytes per screen on average).
+
+The map was designed using [tiled](https://www.mapeditor.org/) exporting JSON
+and processed by a Python tool. See `data/stage.json`.
+
+The binary data includes *n* maps, with each map:
+
+* 1 byte: map data length, not including flags (0 for empty map; no more data included).
+* 1 byte: flags
+* map length bytes: map data (4-bit per tile) H x W x n (compressed with `apultra`)
+* *m* bytes: entity data (0xff for end marker)
+
+The map flags are:
+
+* 0-4: blocked (up, down, left, right)
+* 5-7: tileset
+
+The converter tool expects layers `Map` and `Entities`, and some predefined
+entity type (on the object name).
+
+By default each entity uses one sprite, unless a different weight is set for
+that type (e.g. the "link" entity type to connect screens doesn't use sprites).
+This information is used by the converter to validate that all screens are
+valid.
+
+Entities can be persistent (tracking state; e.g. if a door was unlocked),
+otherwise they always respawn when the player enters the screen.
+
+See `tools/map.py` for details.
+
+## Licence
+
+* The source code of the game is licensed [GPL 3.0](gpl-3.0.txt).
+* The assets are licensed [CC-BY-NC-SA](https://creativecommons.org/licenses/by-nc-sa/4.0/).
+
+The tools/libraries included that I don't own have their own copyright notices
+and license (some are public domain, others are open source).