Giter Site home page Giter Site logo

jorgegv / rage1 Goto Github PK

View Code? Open in Web Editor NEW
18.0 18.0 0.0 1.84 MB

RAGE1: Retro Adventure Game Engine, release 1

License: Other

Makefile 1.04% C 19.94% C++ 0.17% Assembly 48.74% Shell 1.04% Perl 29.03% BASIC 0.04%
adventure-game-engine engine fuse unix-spectrum-emulator zx-spectrum

rage1's People

Contributors

jorgegv avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

rage1's Issues

flowgen: add checks ad rules for interacting with elements in non-current screens

It would be useful to have a flowgen action to interact with elements screens different than the current one.

An easy way to pass 1 bit of information from one screen to another would be the following:

  • Add some state to each screen (e.g. add a "state_data" struct inside the map_screen_s structure, and a "flags" field inside). Initially, set the state to 0.
  • Add flowgen actions to set/reset a screen flag, allowing to set it in any screen, not just the current one. Parameters: screen number and flag to set/reset
  • Add flowgen checks to check a screen flag is set/reset
  • Add support to FLOWGEN tool to generate new code

Branch: screen_state

With the above changes, the possible chain of events in the game would be:

  • Something happens in the current screen that makes something change (e.g. a btile state) in other screen
  • Since this would normally be detected with a FLOWGEN rule, the associated triggered action would set a given flag in the other screen's state
  • The other screen would have a ENTER_SCREEN triggered FLOWGEN rule, which would check that flag, and then activate the BTile locally (since it is on the same screen)

doc: write RAGE1 game development tutorial

Write a detailed step-by-step tutorial based on my own development of Famargon.

Share it in z88dk and spectrumcomputing forums

Contents:

  • Introduction to RAGE1
  • Game story and goals
  • Creating the game skeleton
  • Designing the hero
  • Designing the map
  • Creating the tiles
  • Designing the screens
  • Adding some enemies
  • Adding inventory items
  • Adding behaviour rules
  • Special game functions
  • Compiling for 128K
  • Adding sound and music

btile: optimize memory usage for btile type array

In the 1K BSS mentioned in issue #46, 768 bytes correspond to the tile type array which is used to check if a char position on screen is an OBSTACLE, a DECORATION or an ITEM (or something else in the future).

Reducing this array is difficult, because it is accessed very often from several points multiple times, and the speed of calculating the index into the array and returning the item type is critical.

A small test has been tried by packing 4 cells per byte (allowing for 4 tile types - we are using already 3...), but the complexity of calculating the index for returning the tile type made the code larger and it ate most of the memory reduction which was obtained by the packing (from 768 bytes to 192 bytes).

Speed seemed not to be affected very much, though... Some more tests are needed and perhaps this is a good way to scratch a few hundred bytes.

Algorithm ( A = Tile number 0-767; T = Type 0-3 ):

  • GET(A):

    • Addr = A >> 2
    • Byte = [ Addr ]
    • Rot = ( A & 0x03 ) << 1
    • Return: ( Byte >> Rot ) & 0x03
  • SET(A,T):

    • Addr = A >> 2
    • Byte = [ Addr ]
    • Rot = ( A & 0x03 ) << 1
    • Val = ( Byte & ( ~( 0x03 << Rot ) ) ) | ( T & 0x03 )
    • [ Addr ] = Val

Update 1:

  • Tested forcing a __z88dk_fastcall declaration, and packing Address+Tile type in 12 bits, to send just one parameter to the btile_get_tile_type function. Supposedly we were going to gain 576 bytes minus the get/set functions (126 bytes) and minus the calling overhead.
  • It turns out that this calling overhead is big, since we have to pack the parameters before calling btile_get_tile_type. So with this, the game loop isslower (the sprites move way slower), and also, since we have 21 times the function is called, the parameter marshaling overhead eats up almost all memory savings. So with this test, we get a slower game, and just for a gain of ~130 bytes.
  • We'll try without the __z88dk_fastcall convention and no parameter marshaling.

Update 2:

  • I finally got it working with no __z88dk_fastcall convention and no parameter marshaling. EVerything worked fine, and we saved another ~380 bytes!

btile: animated background btiles

Allow for animated btiles.

  • Intended mainly for short and sporadic animation sequences
  • This does not replaces sprites, btiles do not move
  • An animated btile has N frames
  • An animated btile has an animation sequence, which repeats over and over, governed by a repetition delay
  • An animation sequence is a sequence of frame numbers (minimum 2, maximum 16), governed by animation delay
  • This would very well benefit from #85 since there is the potential of reusing several 8x8 tiles between BTILE frames
  • This would also benefit from #106 for better efficiency
  • Reuse the sprite animation sequence code

Tasks:

  • Factor out sprite animation data structure for reuse
  • Factor out code for animation sequence state-machine for reuse (enemy.c)
  • DATAGEN: add support for defining btiles with multiple frames (special case: normal btile with 1 frame)
  • DATAGEN: add support for locating animated frames in a screen (similar animation options as sprites)
  • Add a new table to each screen which contains the animated btiles (btiles with a frame count > 1 and an animation sequence with >1 steps). Since the number of btiles in a screen can be big, the list needs to be precomputed, so that only animated btiles are processed by the animation function.
  • Modify game loop main function to call btile_animate_all function, which animates only animated btiles, extracted from the table indicated in the previous step
  • Conditional compilation: btile definition with more than 1 frame activates build feature ANIMATED_BTILES (temporary: better activate the option when an animated btile is actually used in any screen)
  • Code related to animated btiles must be conditionally compiled wrt that build feature

Notes:

  • According to https://worldofspectrum.org/forums/discussion/11729/ann-sp1-for-z88dk-aka-splib3-sprite-pack-v3-0/p2 , function sp1_PutTilesInv can be used for better efficiency.
  • This function needs the data in a specific format (struct sp1_tp), but I think we can rearrange the BTile data layout to match that, and use that function instead.
  • The point of that function is that the loop for all the N cells of a BTile is done fully in assembler, so it would be just one call to sp1_PutTilesInv instead of N calls to sp1_PrintAtInv. Also, calculations for indexes would be saved.

fix: add multiple checks and actions to flowgen rules

Add multiple CHECK and DO sections in flowgen rules. The flowgen tool already parses this, but it only used the first CHECK and DO action to generate the code (as of now)

It must generate code for all the checks and actions, and the engine must be adapted to run all of them.

Several CHECKs in the same rule is the way to specify AND conditions. Several rules is the way to specify OR conditions.

CHECKs must be evaluated in shortcircuit mode. ACTIONS must be executed in order.

When this code is in place, the specific checks for game ending related to the demo game can be completely removed from the main game loop in the engine source, and thus it will be completely generic.

test: try to optimize BSS data segment

The BSS data segment takes now around 1K and it's mainly composed of static local variables (i.e. local variables defined as "static" inside functions). This was done supposedly for speed reasons: variables with fixed addresses are much faster to handle than (IX+offset) based ones.

Maybe we don't need to optimize for speed in those cases, and those variables can be just declared as local (stack) variables. If this is the case, we woud gain an additional 1K for game code. Stack usage will increase, since local variables that were fixed in memory will now be allocated on the stack.

Tasks:

  • Make a specific branch for this: test_no_local_static_vars
  • Replace all static local declarations for just local ones
  • Make sure everything continues working
  • Merge changes into master (and probably update documentation about optimizations)

enemy: new enemy movement with dual animation sequence

It is interesting to have an enemy movement type that allows to have different animation sequences depending on the direction it is moving. When the multiple animation sequence feature is implemented (#37) this issue is really easy to implement.

Most probably the animations for one direction would be mirrored images from the other one, but this is not required, both can be specified separately.

Animation sequence can change when bouncing horizontally or vertically.

  • Implement #37
  • Implement dual animation sequence and changing it when bouncing horizontally or vertically
  • Test with fully animated sprite (Famargon)

Fire: add animation to bullets

Fire: add animation to bullets

Refactoring bullet animation code with the regular sprite animation code (with animation sequences implemented in #37 ) should make this very easy

Notes:

  • Now that we have multiple bullet sprites for different directions (#91), it should very easy to add this feature
  • Currently, animation management code is duplicated with Hero and Enemy code. We should refactor it into a couple of functions (reset and clocktick) so that animation handling can be reused in hero, enemies, bullets, etc.

datagen: generate game data in multiple datasets

Main goal

  • DATAGEN lays out the game data and generates multiple datasets according to configuration
  • Engine supports multiples datasets and switches between them as needed

Steps

  • Create a global screen_dataset_map table in dataset.h. It should be used in enter_screen for selecting the proper dataset.
  • Modify DATAGEN to split data in different datasets according to configuration
    • Refactor all asset lists in the Perl code:
      • Homogeneize naming (i.e. all_items, all_sprites, all_btiles. etc.)
      • Replace all direct references to assets by slices/array indexing into the global asset lists
    • Split assets between home dataset (always available) and regular datasets (banked)
      • Home dataset:
        • Hero
        • Bullets
        • BTiles used for menu and others
        • Lives BTile
        • Items BTiles
      • Banked datasets: all other assets (btiles, sprites, screens, rules, etc.)
    • Add the DATASET attribute to SCREEN. Any asset used by this screen needs to be included in the same dataset
    • Add the DATASET attribute to BTILE. Any btile with this attribute will be copied to the given dataset, in addition to the datasets containing screens that use this btile. This is intended mainly for btiles used in menus, which should go into the home dataset.
    • Analyze all screens and build a dependency structure for the assets: for each screen and asset type, build a list of the assets used in that screen (indexes into the global asset lists)
    • Refactor the asset output generation routines to accept a list of assets to output instead of using the global variables for each asset type
    • Output datasets one by one, using their asset lists to generate the output.
    • Fix map.c functions that walk all screens for resetting enemies/sprites: Fix bug #51
    • Add game_config setting zx_target, with 48/128 possible values. If not specified, default to 48.
    • If zx_target is 48, ignore datasets and output all assets in the home dataset
    • Adjust Makefile builds for 48/128 modes
  • Output the screen_dataset_map table
  • Add dataset switches in SCREEN_ENTER event
  • Test game screens in different datasets in 128 mode

sprite: optimize sprite drawing with xthresh and ythresh

When we have small sprites (e.g. bullet, which is 5x5 pixels in the demo game), we can optimize the sprite drawing by specifying hthresh and vthresh for the sprite, which indicate what minimum rotation values are needed to draw the external (right and bottom) cells (with small sprites, or sprites that do not fully fill their bounding boxes, these cells may not be needed).

By default hthresh and vthresh are 1, but they can be set to the following for better optimization:

  • XTHRESH: 8 - ( real width % 8 ) + 1
  • YTHRESH: 8 - ( real height % 8 ) + 1
    For this to work we need to know the real width and height of a sprite. This data can be set in GDATA with new REAL_PIXEL_WIDTH and REAL_PIXEL_HEIGHT directives, which DATAGEN can later use to generate sprite initialization code.

This optimization can be applied to all sprites, not just small ones. Since the defaults are 1, DATAGEN should not generate code for changing it if the calculated values for XTHRESH and YTHRESH happen to be the defaults.

sprite: add colours to sprites

Currently sprites are drawn in the default background attributes. Allow each sprite to have a color different from the background, obstacles, hero, etc.

all: add infrastructure to make engine features conditionally compilable for size optimization

URGENT: This issue now is critical for FAMARGON, I have already reached maximum memory size

Also related to #47

The engine should not generate code and/or data for unused features. E.g. if no "items" are used in the game, all item management code should not be included in the final executable.

Solution:

  • Make each code feature/block in engine C source conditionally compilable via #ifdef's
  • Code that is always needed should not be conditionally compilable
  • Create a new features.h generated by DATAGEN, which contains #define's for each feature that DATAgen has generated code for.
  • DATAGEN should start with an empty %features array. While it processes the GDATA files it should add the FEAT_xxxx flags to this array. Finally, when all code is output, it should generate a features.h file which contains the #define's that enable the used features.
  • All C header files should include "features.h"

build: make building under Windows possible

Possible issues:

  • UNIX environments on Windows -> MINGW, WSL2, etc. (for make, perl, m4, etc.)
  • Write BUILD.BAT file to build from scratch - NOT NEEDED
  • Make sure Makefile works fine under Windows and Linux

Refactor game loop condition checks into FLOWGEN

Refactor special conditions into engine (like La Churrera by Mojon Twins), with different conditions to be checked:

  • When: enter screen; exit screen; every game_loop cycle
  • Conditions: all items grabbed, all enemies killed, hot zone,...
  • Actions: end of game,...

Add 128K sound chip support

Add 128K sound chip support: WYZtracker, etc.

Update: seems ArkosTracker is the way to go?

Update 2: Pedro Pimienta recommends Vortex Tracker, and that's included in Z88DK out of the box, so I guess it should be the initial option.

Unfortunately Vortex 2 does not allow sound effects mixed with music. Arkos and WYZ do.

Update 3: Arkos can import Vortex files and export Arkos, so this should be way to go: integrate Arkos in RAGE1, music can be created with Vortex and imported by Arkos.

  • Sound effects in 128K mode
  • Tracker: see #84

Support 128K memory bank switching for bigger games

Support 128K memory bank switching for bigger games.

Development is done in branch banked_game_data

A (WIP) design document for this functionality can be found in that branch, in doc/BANKING-DESIGN.md

Main goal

  • Allow games to use all 8 RAM banks in the ZX Spectrum 128: 3 banks are already used as the standard 48K (5,2,0), allow use of the remaining ones (1,3,4,6,7)
    • Design a memory manager (desired features: RO/RW pages, compressed pages) and memory map
    • Modify RAGE1 tools to locate game data elements in memory according to the memory map
    • Modify RAGE1 tools to generate memory manager configuration
    • Modify engine for multiple datasets/banks
  • Allow compiling for 48K/128K using the same sources - Use case: you start your project compiling for 48 and when memory gets tight, you change to 128 mode with no source changes besides a config option
  • Update documentation

Steps

  • Design a standard memory map (interrupts, heap, code, bss, data)
  • Design memory map and write design document
  • Test new memory map with stubs for:
    • Heap memory management
    • Interrupt management
    • SP1 library
  • Test memory manager:
    • Modify RAGE1 to generate game data in a new section
      • Refactor DATAGEN/FLOWGEN for better generation of mixed ASM/C/H files
      • Create generic sprite/bullet/hero initialization function + Make DATAGEN output sprite definition data + Remove DATAGEN generation of sprite/bullet/hero init functions ( -> this makes screens consist only of data, no code, which is needed to do banking with SDCC)
      • Make DATAGEN generate different C files for data that is always accesible (e.g. Hero/Bullet sprites, game map, which go into the home bank, the same as code), and data that is associated to map screens (assets, which go in the paged memory banks)
      • Integrate FLOWGEN data generation into DATAGEN
      • Generate FLOW data which refers to one single screen contiguous with the rest of screen data
      • Reorder DATAGEN data generation so that all data belonging to a single map screen is contiguous and can be located in the same memory bank
      • Move banked data into high memory banks:
        • Vectorize accesses to game assets via pointers at a known address - see #48
        • Modify Makefile to build banked data binary file (see this link for ideas) - Datasets
        • Compress dataset binaries with ZX0
        • Create r1banktool.pl to manage the bank and TAP layout:
          • Gathers compiled+compressed datasets and packs them out efficiently in the memory banks (searches for dataset_*.zx0 files in datasets dir)
          • Creates the bank_N.bin files in banks directory (to be created). They will be later processed to get TAPs.
          • Generate a dataset_map.asm source file which will be included in the main program. This file maps dataset -> memory bank and start address so that whenever a dataset needs to be loaded, we know where to find it.
          • Generate a BASIC loader that loads the datasets in the memory banks in a fixed order
          • Generate also a bank_bins.cfg which contains the bank numbers in the same order that the BASIC loader is going to load them.
          • Integrate these changes into the general build
        • Modify Makefile to create the final TAP file with the generated BASIC loader, the main program and the TAPs for all the used banks. The bank TAPs are used according to the previously generated banks.cfg
        • Modify RAGE1 test program to initialize memory manager at start and load the original data at the LOWMEM page frame
  • Design and document final heap location
    • Adjust heap start and size
    • Document heap configuration and maximum values for e.g. SP1 sprites, which is the main (only?) heap user
  • Refactor and generalize: mutiple datasets, "resident" (always available) home_dataset.
    • Document the design of 48/128 compilation mode
    • Make DATAGEN generate game data in multiple datasets - see #49
    • Conditional 48/128 compilation based on a game_config setting (e.g. zx_target directive, with 48/128 values). For 48mode, only home_dataset is compiled, all assets go there and the banking functions are not used. For 128 mode, all functionality from this issue is brought in.
  • Update USAGE-OVERVIEW.md with instructions for 48/128 builds

This issue has originated the following non-trivial design changes:

  • Complete memory map redesign
  • Classification of assets into home and banked types
  • Complex build system with multiple TAP blocks and custom BASIC loader
  • Explicit heap dimensioning and initialization
  • Split asset state and configuration for all asset types

sprite: allow sprites with multiple animation sequences

Allow to specify multiple animation sequences for a sprite:

  • Each sprite has a "database" of frames (table)
  • A sequence is an array of frame numbers
  • A sequence is repeated after a final delay
  • A sprite has a current animation sequence
  • A sprite has a current sequence counter which is used to index the sequence and get the frame number to display
  • A sprite has several counters for the different animation phases

Development started in branch refactor_animation_and_graphics_data

all: replace indirect pointer code with precalculated constants

There are lots of places where the code is generic and uses several pointers to access things, assets, code, etc. Accessing these pointers is easy from C, but it generates lots of assembler code because of the indirections and the intermediate variable needed.

These generality makes sense if the code would be included as a library, since it should be capable of handling different setups. But since currently the RAGE code is designed to be compiled with every build, and it already depends of constants that are defined in game_data.h (which is generated and completely depends on the concrete game), it turns out that lots of those indirections can be precalculated at compile time with constants.

Example: the code for checking hero movements (i.e. hero is over a hotzone, hero can grab an item, hero can move in any direction, etc.) is generic and allows a hero sprite of any size. But the hero sprite does not change during the game, it is always the same size; this code can thus be optimized by defining some constants for the hero sprite dimensions in game_data.h, and using them in the code. This will make the code much smaller and quicker (less instructions in a critical path).

Tasks:

  • Replace generic code with compile time constants:
    • hero movement check loops (hero.c)
    • bullet movement (bullet.c)
    • enemy movement (enemy.c)
    • flow (flow.c)
  • ...(add here anything else that might be optimized this way)...

datagen: add functionality to edit map screens with text-mode strings

datagen: add functionality to edit map screens with text-mode strings in a similar way as PIXELS lines in tiles.

  • Use DEFINE lines to specify digraphs (2-char sequences that are used for positioning big tiles in a 32x24 cell map).
  • Use 24 SCREEN_DATA lines of 64 chars (32 digraphs) each, to indicate what tiles go into which positions
  • See doc/MAP-SCREEN-DATA-DESIGN.md for details

optimize flag fields in all structures

Most flags fields are 16 bits, but this is overkill for most situations. The unused extra bytes quickly add up in a game with lots of screens, btiles, enemies, etc.

We'd better make flags 8-bit instead of 16-bit, and also remove all currently unused flags fields in data structures. Some of them were put there "just in case", but we are tight on memory, so we will remove unused ones and add any flags only when needed.

Savings are to be expected in data and also in code, since code for 8-bit checks is normally shorter than 16-bit checks

Tasks:

  • Make all flags fields 8-bit - All done, except debug_flags
  • Remove unused flags fields - No one removed, all that exist are used

game_loop: migrate hotzone detection to flowgen rules

If hotzone detection is done in flowgen rules, then we can use the already existing checks and actions in combination with hotzones.

How to do it:

  • A new flowgen rule check of type HERO_INSIDE_HOTZONE should be added. This check should do the same checks that are done in the game_loop function check_hotzones
  • A new flowgen rule action of type WARP_TO_SCREEN should be added. This action should receive all the parameters the HOTZONE definition had ( DEST_SCREEN, DEST_HERO_X and DEST_HERO_Y)
  • The action function for this rule action should do the same that was done for switching screens in function hero_check_if_inside_hotzones
  • Since hotzones are now defined in FLOWGEN rules, its functionality should be removed from DATAGEN
  • HOTZONE functionality in GDATA files should be moved to flow rules

Support side-view games

Add support for platform games in side view (i.e. gravity and floor detection support).

Since obstacle detection is already implemented (it's in the basics), only gravity management needs to be done. The platforms are obstacles.

Notes:

  • With the current obstacle detection code and the implementation of gravity, Mario-style platforms can already be handled (if Mario jumps below a brick, he does not pass through, but bounces down; but if he falls on a brick, he keeps on it)
  • We can define a new obstacle type TT_PLATFORM that can be passed through from below, but not from above (if the hero hits it from below, it behaves like a DECORATION but if the hero falls on it, it behaves like an OBSTACLE)

fix: btiles should be referenced by name, and their objects indexed

Several objects that appear in screens are drawn via BTiles (obstacles, decorations and items). THey normally have a NAME field which references the BTILE whith souhd be used to draw the object. THis blurs the distinction between the object and the tile, which is problematic because the same BTILE can be reused for several objects.

Objects and btiles should differentiated:

  • Object definitions should have a NAME field and a BTILE field. The NAME should be used for referencing the object elsewhere (flow rules, etc.) and the BTILE should be used for drawing.
  • Object types that should be migrated:
    • Obstacles
    • Decorations
    • Items

Question about the Sounds

Hi Jorge,

I have a simple question about your Sound system.
Why haven't you used the beepfx library (there are available into the z88dk) ? Instead that, you have extrated the asm code and you have included into your game. What's the benefict ?

thanks in advance.

map: alloc/free SP1 sprite structs when entering/exiting screen

Sprites are currently managed this way:

  • Sprite graphics data is statically allocated
  • All sprites are allocated at once at the beginning of the program execution
  • They remain allocated forever

Drawbacks:

  • Memory does not scale: the demo game has 4 sprites in only 2 screens, but a real game can have, say 200 sprites (e.g. 50 screens, 4 sprites each). It makes no sense to allocate 200 sprites which are not used most of the time
  • Initialization does not scale: it takes a short time to init 4 sprites, but 200 would surely add to the game startup time
  • It is not modular, which complicates the picture for 128k banking

Change to:

  • Each screen has 2 function pointers: sprite initialization and sprite destruction. these functions create and destroy the sprites for each screen.
  • The SP1 sprite structures for a screen's sprites are created only while the hero is on a given screen
  • SP1 sprites are allocated on ENTER_SCREEN and are freed on EXIT_SCREEN. Normally only a small number of sprites will exist on any given screen, so allocating and deallocating them should be quick and scale well
  • These functions can also be autogenerated from the game_data files: DATAGEN currently generates one big function to initialize all of them, but instead, 2 short functions per screen could be generated with roughly the same code size.

Benefits:

  • Screens are more independent between them
  • It simplifies map management for a hipothetical banking routine, since screens are more "self-contained"
  • This means we can simply add more screens to our map with the only restriction of the available memory

map: add random placement of background tiles

Currently there can be one BACKGROUND element in a given map screen, defined as a rectangle which is completely with one given tile of type DECORATION. These background tiles are currently statically generated by DATAGEN.

It would be nice to add a PROBABILITY setting, which applies the same filling algorithm to the given rectangle, but which finally puts the BG tile or not depending on its PROBABILITY. This can make for nice screens with randomly placed background elements (e.g. stars on the sky, grass on the floor, trees, etc.)

PROBABILITY can be a 0-255 setting specified in the BACKGROUND directive in GDATA file for the given map screen. When placing a background element, a random number 0-255 can be generated. If it is less or equal than PROBABILITY, then the tile is drawn. If it is greater, it is not. This way, 0-255 maps exactly to the regular probability interval (0,1), with 0 = never show and 1 = always show.

Finally, this code should be added to the engine and removed from DATAGEN. Memory wise, it's much cheaper to include a definition of a rectangle, btile and probability than several dozens of automatically generated static background tiles. For this, a "background" section should be added to the map_screen_s structure, and the relevant code to use it for drawing the map screen.

Also for this to work we need a pseudo random number generator.

game_state: split configuration and state for all asset types

Some game assets (e.g. btiles, enemies,...) have some kind of state which is reset at game startup, and changes during the game (flags field, movement coordinates, etc.); this state is currently stored in the asset definition structure for some asset types.

This is fine when the assets don't "move" in memory; but when memory banking is introduced, assets are stored compressed in "read-only" memory and can reloaded to the working memory zone at ay time. That state would then get reset when switching out a dataset and bringing it back in later.

The general problem is that Asset configuration and state are intermixed in the same data structures. All asset types need to be audited and any state extracted out of them and instead added to game_state structure.

Goals:

  • All asset state is stored into game_state and removed from struct map_screen_s
  • Assets can then be stored in read-only memory

Steps:

  • Review fields Inside struct map_screen_s:
    • Review enemy_data (they can be killed) - Reviewed: flags, movement
    • Review btile_data (they can be enabled/disabled) - Reviewed: flags
    • Review state_data (screen flags can change) - Reviewed: flags
    • Review item_data (they can be grabbed) - Reviewed: no state data (item state is held in inventory global var)
    • Review hotzone_data (they can be enabled/disabled) - Reviewed: flags
  • Migrate fields which have state and are within struct map_screen_s to entries in screen asset state tables:
    • enemy_data
    • btile_data
    • Screen flags (removed, since state number 0 is always reserved for the screen state)
    • hotzone_data

For detailed solution, see section Issues with banked screen data and asset state during the game in doc/BANKING-DESIGN.md

datagen: allow HOTZONE dimensions and positioning in pixels in addition to char cells

Tasks:

In HOTZONE definition, the current behaviour is: position with ROW,COL params, dimension with WIDTH, HEIGHT params. Numbers are in char-cells.

Additionally we want:

  • Allow parameters X,Y, PIX_WIDTH,PIX_HEIGHT they are taken as pixels
  • When using params ROW,COL,WIDTH,HEIGHT they are taken as cells
  • If both params X,Y and ROW,COL are present (they shouldn't), pixels dimensions and positioning are assumed
  • Internally store all HOTZONE coordinates and dimensions in pixels, not in cells (currently they are specified in cells)
  • Implement hero_inside_hotzone() function by using collision functions.

flow: add user variables to flow rules checks and actions

Add user variables in flow rule checks and actions

  • Variables have values that are uint8_t
  • Maximum number of variables: 256 (variable id is a uint8_t)
  • Variable IDs are manually managed: if you use var with ID=3 you take care of what it means
  • Add a memory area for user variables (only variables that are used are allocated)
  • Add rule checks for variables: VAR_IS_EQUAL, VAR_IS_GREATER_THAN, VAR_IS_LESS_THAN
  • Add rule actions for variables: VAR_STORE, VAR_INC, VAR_ADD, VAR_DEC, VAR_SUB

sprite: refactor and fix sprite code used for enemies in map screens

Nomenclature for enemies in screens is confusing: they are called "sprites" but they should be named "enemies". This makes code difficult to read and modify.

  • Enemy management code in sprite.h and sprite.c should be separated into new enemy.h and enemy.c
  • All code using those should be fixed (map.c, hero.c, etc.)
  • DATAGEN new syntax for ENEMY lines in SCREEN sections
  • DATAGEN should be fixed to generate the correct code with the new format
  • DATAGEN documentation should updated
  • GDATA files should be upgraded to the new syntax

data: access game assets via pointers in fixed memory address

In order to enable data banking in the extra memory banks of the ZX 128, all game assets need to be accessed via pointers that are changed whenever a bank change is needed. Tasks:

  • Compilation of data to a fixed memory address (the page frame: 0x5b00)
  • Every banked data file must start with a struct which contains pointers to the global asset tables included in that page: Sprites, Tiles, Screens, Flow rules, etc. The starting address of this struct is known (0x5b00), and the remaining data inside the page is self-contained with respect to those pointers.
  • There must be global asset tables for Sprites, Tiles, Screens, Flow rules, etc, which are changed whenever a new page is brought into the page frame.

hero: have a singular sprite/animation for steady (not moving) position

Make the hero have a sprite/animation sequence for the steady state.

  • Change DATAGEN to allow specifying the standby sprite for each movement direction
  • Change hero moving function so that if no movement is detected, steady sprite for the last movemenet direction is selected and shown

branch: sprite_with_steady_position

fix: refactor item list generation in DATAGEN

Currently, items in C code are generated as a global item list, and pointers to items in the screens that contain them. This is the correct approach.

In the generation tool datagen.pl, items are stored inside the screens, and the global item list contains pointers to the items in the screens.

datagen.pl needs to be fixed to store the items the same way as the generated C code.

map: enhanced complete map generation with text drawing

Currently, we can "draw" a screen layout with text characters, digraphs,etc. and the SCREEN_DATA directive.

We could have an enhanced version of that which would allow:

  • Draw and define not just one screen, but a complete map
  • Take care of automatic hotzones for switching from one screen to the adjacent ones
  • Support adding more items to the map via the already existing directives
  • Optimize the map by removing the empty screens (i.e. you can define a non-rectangular map with its bounding box and only the needed screens will be created)
  • Allow all this to complement the existing map definition infrastructure, not replace it

datagen: syntax checker and data linter

Make DATAGEN tool strictly check the syntax of the input files and elements according to the documentation, so that errors are more informative and can be more easily solved.

Design:

  • A tree can be built with the possible child nodes that each directive can/should have.
    OR:
  • Up to now, data input and checking in DATAGEN is separated from the data output functions. The data generation step is quite (completely?) segregated from the data input step.
  • We can ensure that the separation between data input and code generation is complete (if it is not)
  • We must also ensure that no die calls during code generations are due to data definition errors. It there are some cases of this, the checks and errors should be moved to the functions before code generation.
  • In the code generation stage, the only die's allowed are those for no write access, error writing files, etc. but we must be sure that the game data can be correctly generated with the data that has been read from the GDATA files.
  • Once we have ensured that the separation between data input and code generation is complete, we can add additional checks to the data input stage without disturbing the code generation stage. We will use the documentation to ensure that all the documented limits are also checked and enforced in the data input steps.
  • Then we can add a new flag to datagen.pl let's say, -v (for "verification"), or reuse -c (for "check") to indicate that we only want to check the syntax of the GDATA files
  • In datagen.pl we can check this flag just before the data generation functions, and end with a success message if it was supplied. If we reach that place, it means that GDATA file loading was successful, since if not we would have die'd in previous functions.
  • And if the "syntax check" is not supplied, continue as it is now, and generate all the code.

Tasks:

  • Ensure that no checks are done during code generation stage. If there are some, migrate the checks to the data input stage
  • Ensure that errors during code generation are only generated due to file conditions: no permissions, no disk space, etc.
  • Add "syntax check" flag and make DATAGEN stop with success message if the flag is supplied, instead of generating game code
  • Review DATAGEN documentation and ensure that all limitations mentioned there are also checked and reported by datagen.pl. Add new checks if needed to the data input stage.

btile: add HARMFUL btiles

Besides the TT_DECORATION and TT_OBSTACLE btile types, there should btiles that kill you when you touch them. This new type makes a good match for #35 , so that the player can be aware that something that moves might kill the hero.

Proposed new type: TT_HARMFUL

doc: write a beter QuickStart document

  • Specify detailed step-by-step instructions for reading the code and compiling the demo game.
  • Linux instructions
  • Window instructions (when available and tested)

Refactor sound generation and just include the player

Refactor sound generation and just include the player. Include sounds
in .gdata files, so that only used sounds are generated and included in
the final game

Idea: define a sound bank first, then assign sounds from the bank somewhere else

fix: make screen areas configurables

Screen areas (game_area, lives_area, inventory_area) are not configurable but fixed. They need to be specified in GAME_CONFIG object and split out from the engine.

If it is not done, updating the engine will overwrite the screen area definitions if they are change from the library default.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.