Mercurial > molko
changeset 554:cdbc13ceff85
rpg: do the same for map
author | David Demelier <markand@malikania.fr> |
---|---|
date | Tue, 07 Mar 2023 22:15:35 +0100 |
parents | cb4508f45048 |
children | 6c911cbc1fd7 |
files | examples/CMakeLists.txt examples/example-map/CMakeLists.txt examples/example-map/example-map.c libmlk-example/CMakeLists.txt libmlk-example/assets/sprites/john.png libmlk-example/mlk/example/registry.c libmlk-example/mlk/example/registry.h libmlk-rpg/CMakeLists.txt libmlk-rpg/mlk/rpg/map-file.c libmlk-rpg/mlk/rpg/map-file.h libmlk-rpg/mlk/rpg/map-loader-file.c libmlk-rpg/mlk/rpg/map-loader-file.h libmlk-rpg/mlk/rpg/map-loader.c libmlk-rpg/mlk/rpg/map-loader.h libmlk-rpg/mlk/rpg/map.c libmlk-rpg/mlk/rpg/map.h libmlk-rpg/mlk/rpg/tileset-loader-file.h libmlk-rpg/mlk/rpg/tileset-loader.c libmlk-rpg/mlk/rpg/tileset-loader.h mlk-map/mlk-map.c |
diffstat | 20 files changed, 1047 insertions(+), 522 deletions(-) [+] |
line wrap: on
line diff
--- a/examples/CMakeLists.txt Tue Mar 07 20:58:00 2023 +0100 +++ b/examples/CMakeLists.txt Tue Mar 07 22:15:35 2023 +0100 @@ -29,6 +29,7 @@ example-font example-gridmenu example-label + example-map example-message example-notify example-sprite
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/example-map/CMakeLists.txt Tue Mar 07 22:15:35 2023 +0100 @@ -0,0 +1,33 @@ +# +# CMakeLists.txt -- CMake build system for Molko's Engine +# +# Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> +# +# Permission to use, copy, modify, and/or distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +# + +project(example-map) + +set( + SOURCES + ${example-map_SOURCE_DIR}/example-map.c +) + +mlk_executable( + NAME example-map + FOLDER examples + LIBRARIES libmlk-example + SOURCES ${SOURCES} +) + +source_group(TREE ${example-map_SOURCE_DIR} FILES ${SOURCES})
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/example-map/example-map.c Tue Mar 07 22:15:35 2023 +0100 @@ -0,0 +1,203 @@ +/* + * example-map.c -- example on how to use a map + * + * Copyright (c) 2020-2023 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <assert.h> +#include <stdio.h> +#include <string.h> + +#include <mlk/core/animation.h> +#include <mlk/core/core.h> +#include <mlk/core/err.h> +#include <mlk/core/event.h> +#include <mlk/core/game.h> +#include <mlk/core/image.h> +#include <mlk/core/key.h> +#include <mlk/core/painter.h> +#include <mlk/core/panic.h> +#include <mlk/core/state.h> +#include <mlk/core/sys.h> +#include <mlk/core/trace.h> +#include <mlk/core/util.h> +#include <mlk/core/window.h> + +#include <mlk/ui/label.h> +#include <mlk/ui/ui.h> + +#include <mlk/rpg/map-loader-file.h> +#include <mlk/rpg/map-loader.h> +#include <mlk/rpg/map.h> +#include <mlk/rpg/tileset-loader-file.h> +#include <mlk/rpg/tileset-loader.h> +#include <mlk/rpg/tileset.h> + +#include <mlk/example/example.h> +#include <mlk/example/registry.h> + +#include <assets/maps/world.h> +#include <assets/tilesets/world.h> + +static struct mlk_tileset_loader_file tileset_loader_file; +static struct mlk_tileset_loader tileset_loader; +static struct mlk_tileset tileset; + +static struct mlk_map_loader_file map_loader_file; +static struct mlk_map_loader map_loader; +static struct mlk_map map; + +static const struct { + const char *basename; + struct mlk_texture *texture; +} table_textures[] = { + { "world.png", &mlk_registry_textures[MLK_REGISTRY_TEXTURE_WORLD] }, + { "animation-water.png", &mlk_registry_textures[MLK_REGISTRY_TEXTURE_WATER] }, + { NULL, NULL } +}; + +static struct mlk_texture * +init_texture(struct mlk_tileset_loader *loader, const char *ident) +{ + (void)loader; + + char filepath[MLK_PATH_MAX], filename[FILENAME_MAX + 1]; + + mlk_util_strlcpy(filepath, ident, sizeof (filepath)); + mlk_util_strlcpy(filename, mlk_util_basename(filepath), sizeof (filename)); + mlk_tracef("Searching for texture %s", filename); + + for (size_t i = 0; table_textures[i].basename != NULL; ++i) + if (strcmp(table_textures[i].basename, filename) == 0) + return table_textures[i].texture; + + return NULL; +} + +struct mlk_tileset * +init_tileset(struct mlk_map_loader *loader, struct mlk_map *map, const char *ident) +{ + (void)loader; + (void)map; + (void)ident; + + /* + * For this example, we assume that the ident contains "world.tileset" + * because there are no other in the map we will load. + */ + mlk_tracef("Searching tileset %s", ident); + + if (mlk_tileset_loader_openmem(&tileset_loader, &tileset, assets_tilesets_world, sizeof (assets_tilesets_world)) < 0) + mlk_panic(); + + return &tileset; +} + +static void +init(void) +{ + if (mlk_example_init("example-map") < 0) + mlk_panic(); + + /* + * Just like in example-tileset.c, we want to open images from the + * registry which is not supported by itself in + * mlk_tileset_loader_file. + */ + mlk_tileset_loader_file_init(&tileset_loader_file, &tileset_loader, ""); + tileset_loader.init_texture = init_texture; + + /* + * Create our map loader. It will also search for a tileset to be found + * on disk by default which we would like to avoid. We override the + * init_tileset function. + */ + mlk_map_loader_file_init(&map_loader_file, &map_loader, ""); + map_loader.init_tileset = init_tileset; + + if (mlk_map_loader_openmem(&map_loader, &map, assets_maps_world, sizeof (assets_maps_world)) < 0) + mlk_panic(); + + // TODO: this not handled by the map yet. + map.player_sprite = &mlk_registry_sprites[MLK_REGISTRY_TEXTURE_JOHN]; + mlk_map_init(&map); +} + +static void +handle(struct mlk_state *st, const union mlk_event *ev) +{ + (void)st; + + switch (ev->type) { + case MLK_EVENT_QUIT: + mlk_game_quit(); + break; + default: + mlk_map_handle(&map, ev); + break; + } +} + +static void +update(struct mlk_state *st, unsigned int ticks) +{ + (void)st; + + mlk_map_update(&map, ticks); +} + +static void +draw(struct mlk_state *st) +{ + (void)st; + + mlk_painter_set_color(MLK_EXAMPLE_BG); + mlk_painter_clear(); + mlk_map_draw(&map); + mlk_painter_present(); +} + +static void +run(void) +{ + struct mlk_state state = { + .handle = handle, + .update = update, + .draw = draw + }; + + mlk_game_init(); + mlk_game_push(&state); + mlk_game_loop(); +} + +static void +quit(void) +{ + mlk_map_loader_file_finish(&map_loader_file); + mlk_tileset_loader_file_finish(&tileset_loader_file); + mlk_example_finish(); +} + +int +main(int argc, char **argv) +{ + (void)argc; + (void)argv; + + init(); + run(); + quit(); +}
--- a/libmlk-example/CMakeLists.txt Tue Mar 07 20:58:00 2023 +0100 +++ b/libmlk-example/CMakeLists.txt Tue Mar 07 22:15:35 2023 +0100 @@ -43,6 +43,7 @@ ${libmlk-example_SOURCE_DIR}/assets/sprites/explosion.png ${libmlk-example_SOURCE_DIR}/assets/sprites/john-sword.png ${libmlk-example_SOURCE_DIR}/assets/sprites/john-walk.png + ${libmlk-example_SOURCE_DIR}/assets/sprites/john.png ${libmlk-example_SOURCE_DIR}/assets/sprites/numbers.png ${libmlk-example_SOURCE_DIR}/assets/sprites/people.png ${libmlk-example_SOURCE_DIR}/assets/sprites/ui-cursor.png
--- a/libmlk-example/mlk/example/registry.c Tue Mar 07 20:58:00 2023 +0100 +++ b/libmlk-example/mlk/example/registry.c Tue Mar 07 22:15:35 2023 +0100 @@ -35,6 +35,7 @@ #include <assets/sprites/explosion.h> #include <assets/sprites/john-sword.h> #include <assets/sprites/john-walk.h> +#include <assets/sprites/john.h> #include <assets/sprites/numbers.h> #include <assets/sprites/people.h> #include <assets/sprites/ui-cursor.h> @@ -78,6 +79,7 @@ MLK_REGISTRY_TEXTURE(MLK_REGISTRY_TEXTURE_CURSOR, assets_sprites_ui_cursor, 24, 24), MLK_REGISTRY_TEXTURE(MLK_REGISTRY_TEXTURE_EXPLOSION, assets_sprites_explosion, 256, 256), MLK_REGISTRY_TEXTURE(MLK_REGISTRY_TEXTURE_WATER, assets_sprites_water, 48, 48), + MLK_REGISTRY_TEXTURE(MLK_REGISTRY_TEXTURE_JOHN, assets_sprites_john, 48, 48), MLK_REGISTRY_TEXTURE(MLK_REGISTRY_TEXTURE_JOHN_SWORD, assets_sprites_john_sword, 256, 256), MLK_REGISTRY_TEXTURE(MLK_REGISTRY_TEXTURE_JOHN_WALK, assets_sprites_john_walk, 256, 256), MLK_REGISTRY_TEXTURE(MLK_REGISTRY_TEXTURE_HAUNTED_WOOD, assets_images_haunted_wood, 0, 0),
--- a/libmlk-example/mlk/example/registry.h Tue Mar 07 20:58:00 2023 +0100 +++ b/libmlk-example/mlk/example/registry.h Tue Mar 07 22:15:35 2023 +0100 @@ -34,6 +34,7 @@ MLK_REGISTRY_TEXTURE_WATER, /* Characters. */ + MLK_REGISTRY_TEXTURE_JOHN, MLK_REGISTRY_TEXTURE_JOHN_WALK, MLK_REGISTRY_TEXTURE_JOHN_SWORD, MLK_REGISTRY_TEXTURE_PEOPLE,
--- a/libmlk-rpg/CMakeLists.txt Tue Mar 07 20:58:00 2023 +0100 +++ b/libmlk-rpg/CMakeLists.txt Tue Mar 07 22:15:35 2023 +0100 @@ -20,6 +20,12 @@ set( SOURCES + ${libmlk-rpg_SOURCE_DIR}/mlk/rpg/map-loader-file.c + ${libmlk-rpg_SOURCE_DIR}/mlk/rpg/map-loader-file.h + ${libmlk-rpg_SOURCE_DIR}/mlk/rpg/map-loader.c + ${libmlk-rpg_SOURCE_DIR}/mlk/rpg/map-loader.h + ${libmlk-rpg_SOURCE_DIR}/mlk/rpg/map.c + ${libmlk-rpg_SOURCE_DIR}/mlk/rpg/map.h ${libmlk-rpg_SOURCE_DIR}/mlk/rpg/message.c ${libmlk-rpg_SOURCE_DIR}/mlk/rpg/message.h ${libmlk-rpg_SOURCE_DIR}/mlk/rpg/property.c
--- a/libmlk-rpg/mlk/rpg/map-file.c Tue Mar 07 20:58:00 2023 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,310 +0,0 @@ -/* - * map-file.c -- map file loader - * - * Copyright (c) 2020-2023 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <assert.h> -#include <errno.h> -#include <limits.h> -#include <stddef.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include <mlk/util/util.h> - -#include <mlk/core/alloc.h> -#include <mlk/core/image.h> -#include <mlk/core/trace.h> -#include <mlk/core/util.h> - -#include "map-file.h" - -#define MAX_F(v) MAX_F_(v) -#define MAX_F_(v) "%" #v "[^\n|]" - -struct context { - struct map_file *mf; /* Map loader. */ - struct map *map; /* Map object to fill. */ - FILE *fp; /* Map file pointer. */ - char basedir[MLK_PATH_MAX]; /* Parent map directory */ -}; - -static int -parse_layer_tiles(struct context *ctx, const char *layer_name) -{ - enum map_layer_type layer_type; - size_t amount, current; - - if (strcmp(layer_name, "background") == 0) - layer_type = MAP_LAYER_TYPE_BACKGROUND; - else if (strcmp(layer_name, "foreground") == 0) - layer_type = MAP_LAYER_TYPE_FOREGROUND; - else if (strcmp(layer_name, "above") == 0) - layer_type = MAP_LAYER_TYPE_ABOVE; - else - return mlk_errf("invalid layer type: %s", layer_name); - - amount = ctx->map->columns * ctx->map->rows; - current = 0; - - /* - * The next line after a layer declaration is a list of plain integer - * that fill the layer tiles. - */ - if (!(ctx->mf->layers[layer_type].tiles = mlk_alloc_new0(amount, sizeof (unsigned short)))) - return -1; - - for (int tile; fscanf(ctx->fp, "%d\n", &tile) && current < amount; ++current) - ctx->mf->layers[layer_type].tiles[current] = tile; - - ctx->map->layers[layer_type].tiles = ctx->mf->layers[layer_type].tiles; - - return 0; -} - -static int -parse_actions(struct context *ctx) -{ - char exec[128 + 1]; - int x = 0, y = 0, block = 0; - unsigned int w = 0, h = 0; - - while (fscanf(ctx->fp, "%d|%d|%u|%u|%d|%128[^\n]\n", &x, &y, &w, &h, &block, exec) >= 5) { - struct map_block *reg; - - if (!ctx->mf->load_action) { - mlk_tracef("ignoring action %d,%d,%u,%u,%d,%s", x, y, w, h, block, exec); - continue; - } - - ctx->mf->load_action(ctx->map, x, y, w, h, exec); - - /* - * Actions do not have concept of collisions because they are - * not only used on maps. The map structure has its very own - * object to manage collisions but the .map file use the same - * directive for simplicity. So create a block region if the - * directive has one. - */ - if (block) { - if (!(reg = mlk_alloc_pool_new(&ctx->mf->blocks))) - return -1; - - reg->x = x; - reg->y = y; - reg->w = w; - reg->h = h; - } - } - - /* Reference the blocks array from map_file. */ - ctx->map->blocks = ctx->mf->blocks.data; - ctx->map->blocksz = ctx->mf->blocks.size; - - return 0; -} - -static int -parse_layer(struct context *ctx, const char *line) -{ - char layer_name[32 + 1] = {0}; - - /* Check if weight/height has been specified. */ - if (ctx->map->columns == 0 || ctx->map->rows == 0) - return mlk_errf("missing map dimensions before layer"); - - /* Determine layer type. */ - if (sscanf(line, "layer|%32s", layer_name) <= 0) - return mlk_errf("missing layer type definition"); - - if (strcmp(layer_name, "actions") == 0) - return parse_actions(ctx); - - return parse_layer_tiles(ctx, layer_name); -} - -static int -parse_tileset(struct context *ctx, const char *line) -{ - char path[MLK_PATH_MAX] = {0}, *p; - struct map_file *mf = ctx->mf; - struct tileset_file *tf = &mf->tileset_file; - - if (!(p = strchr(line, '|'))) - return mlk_errf("could not parse tileset"); - - snprintf(path, sizeof (path), "%s/%s", ctx->basedir, p + 1); - - if (tileset_file_open(tf, &mf->tileset, path) < 0) - return -1; - - ctx->map->tileset = &mf->tileset; - - return 0; -} - -static int -parse_title(struct context *ctx, const char *line) -{ - if (sscanf(line, "title|" MAX_F(MAP_FILE_TITLE_MAX), ctx->mf->title) != 1 || strlen(ctx->mf->title) == 0) - return mlk_errf("null map title"); - - ctx->map->title = ctx->mf->title; - - return 0; -} - -static int -parse_columns(struct context *ctx, const char *line) -{ - if (sscanf(line, "columns|%u", &ctx->map->columns) != 1 || ctx->map->columns == 0) - return mlk_errf("null map columns"); - - return 0; -} - -static int -parse_rows(struct context *ctx, const char *line) -{ - if (sscanf(line, "rows|%u", &ctx->map->rows) != 1 || ctx->map->rows == 0) - return mlk_errf("null map rows"); - - return 0; -} - -static int -parse_origin(struct context *ctx, const char *line) -{ - if (sscanf(line, "origin|%d|%d", &ctx->map->player_x, &ctx->map->player_y) != 2) - return mlk_errf("invalid origin"); - - return 0; -} - -static int -parse_line(struct context *ctx, const char *line) -{ - static const struct { - const char *property; - int (*read)(struct context *, const char *); - } props[] = { - { "title", parse_title }, - { "columns", parse_columns }, - { "rows", parse_rows }, - { "tileset", parse_tileset }, - { "origin", parse_origin }, - { "layer", parse_layer }, - }; - - for (size_t i = 0; i < MLK_UTIL_SIZE(props); ++i) - if (strncmp(line, props[i].property, strlen(props[i].property)) == 0) - return props[i].read(ctx, line); - - return 0; -} - -static int -parse(struct context *ctx, const char *path) -{ - char line[1024], basedir[MLK_PATH_MAX]; - - mlk_util_strlcpy(basedir, path, sizeof (basedir)); - mlk_util_strlcpy(ctx->basedir, mlk_util_dirname(basedir), sizeof (ctx->basedir)); - - while (fgets(line, sizeof (line), ctx->fp)) { - /* Remove \n if any */ - line[strcspn(line, "\r\n")] = '\0'; - - if (parse_line(ctx, line) < 0) - return -1; - } - - return 0; -} - -static int -check(struct map *map) -{ - /* - * Check that we have parsed every required components. - */ - if (!map->title) - return mlk_errf("missing title"); - - /* - * We don't need to check width/height because parsing layers and - * tilesets already check for their presence, so only check layers. - */ - if (!map->layers[0].tiles) - return mlk_errf("missing background layer"); - if (!map->layers[1].tiles) - return mlk_errf("missing foreground layer"); - if (!tileset_ok(map->tileset)) - return mlk_errf("missing tileset"); - - return 0; -} - -int -map_file_open(struct map_file *file, struct map *map, const char *path) -{ - assert(file); - assert(path); - assert(map); - - struct context ctx = { - .mf = file, - .map = map, - }; - int ret = 0; - - memset(map, 0, sizeof (*map)); - mlk_alloc_pool_init(&file->blocks, 16, sizeof (*map->blocks), NULL); - - if (!(ctx.fp = fopen(path, "r"))) - goto fail; - if ((ret = parse(&ctx, path)) < 0 || (ret = check(map)) < 0) - goto fail; - - fclose(ctx.fp); - - return 0; - -fail: - map_finish(map); - map_file_finish(file); - - if (ctx.fp) - fclose(ctx.fp); - - return -1; -} - -void -map_file_finish(struct map_file *file) -{ - assert(file); - - mlk_alloc_free(file->layers[0].tiles); - mlk_alloc_free(file->layers[1].tiles); - mlk_alloc_free(file->layers[2].tiles); - - tileset_file_finish(&file->tileset_file); - mlk_alloc_pool_finish(&file->blocks); - - memset(file, 0, sizeof (*file)); -}
--- a/libmlk-rpg/mlk/rpg/map-file.h Tue Mar 07 20:58:00 2023 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,56 +0,0 @@ -/* - * map-file.h -- map file loader - * - * Copyright (c) 2020-2023 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MLK_RPG_MAP_FILE_H -#define MLK_RPG_MAP_FILE_H - -#include <mlk/core/alloc.h> -#include <mlk/core/sprite.h> -#include <mlk/core/texture.h> - -#include "map.h" -#include "tileset.h" -#include "tileset-loader.h" - -#define MAP_FILE_TITLE_MAX 64 - -struct map_file { - void (*load_action)(struct map *, int, int, int, int, const char *); - - char title[MAP_FILE_TITLE_MAX]; - struct map_layer layers[MAP_LAYER_TYPE_NUM]; - struct tileset_file tileset_file; - struct mlk_tileset tileset; - struct mlk_alloc_pool blocks; -}; - -#if defined(__cplusplus) -extern "C" { -#endif - -int -map_file_open(struct map_file *file, struct map *map, const char *path); - -void -map_file_finish(struct map_file *file); - -#if defined(__cplusplus) -} -#endif - -#endif /* !MLK_RPG_MAP_FILE_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/mlk/rpg/map-loader-file.c Tue Mar 07 22:15:35 2023 +0100 @@ -0,0 +1,110 @@ +/* + * map-loader-file.c -- map file loader implementation + * + * Copyright (c) 2020-2023 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <assert.h> + +#include <mlk/core/alloc.h> + +#include "map-loader-file.h" +#include "map-loader.h" +#include "map.h" +#include "tileset-loader.h" + +static struct mlk_tileset * +init_tileset(struct mlk_map_loader *self, + struct mlk_map *map, + const char *ident) +{ + (void)map; + + struct mlk_map_loader_file *file = self->data; + char path[MLK_PATH_MAX]; + + snprintf(path, sizeof (path), "%s/%s", file->directory, ident); + + if (mlk_tileset_loader_open(file->tileset_loader, &file->tileset, path) < 0) + return NULL; + + return &file->tileset; +} + +static unsigned int * +alloc_tiles(struct mlk_map_loader *self, + struct mlk_map *map, + enum mlk_map_layer_type type, + size_t n) +{ + (void)map; + + struct mlk_map_loader_file *file = self->data; + + return file->tiles[type] = mlk_alloc_new0(n, sizeof (unsigned int)); +} + +static struct mlk_map_block * +expand_blocks(struct mlk_map_loader *self, + struct mlk_map_block *blocks, + size_t blocksz) +{ + struct mlk_map_loader_file *file = self->data; + struct mlk_map_block *ptr; + + if (!file->blocks) + ptr = mlk_alloc_new0(1, sizeof (*ptr)); + else + ptr = mlk_alloc_expand(file->blocks, blocksz); + + if (ptr) + file->blocks = blocks; + + return ptr; +} + +void +mlk_map_loader_file_init(struct mlk_map_loader_file *file, + struct mlk_map_loader *loader, + const char *filename) +{ + assert(file); + assert(loader); + + char filepath[MLK_PATH_MAX]; + + /* Determine base filename base directory. */ + mlk_util_strlcpy(filepath, filename, sizeof (filepath)); + mlk_util_strlcpy(file->directory, mlk_util_dirname(filepath), sizeof (file->directory)); + + loader->data = file; + loader->init_tileset = init_tileset; + loader->alloc_tiles = alloc_tiles; + loader->expand_blocks = expand_blocks; +} + +void +mlk_map_loader_file_finish(struct mlk_map_loader_file *file) +{ + assert(file); + + for (int i = 0; i < MLK_MAP_LAYER_TYPE_LAST; ++i) { + mlk_alloc_free(file->tiles[i]); + file->tiles[i] = NULL; + } + + mlk_alloc_free(file->blocks); + file->blocks = NULL; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/mlk/rpg/map-loader-file.h Tue Mar 07 22:15:35 2023 +0100 @@ -0,0 +1,89 @@ +/* + * map-loader-file.h -- map file loader implementation + * + * Copyright (c) 2020-2023 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MLK_RPG_MAP_LOADER_FILE_H +#define MLK_RPG_MAP_LOADER_FILE_H + +/** + * \file map-loader-file.h + * \brief Map file loader implementation + */ + +#include <mlk/util/util.h> + +#include "map.h" +#include "tileset.h" + +struct mlk_map_loader; +struct mlk_tileset_loader; + +/** + * \struct mlk_map_loader_file + * \brief Map loader file structure + */ +struct mlk_map_loader_file { + /** + * (read-only) + * + * Computed map file directory. + */ + char directory[MLK_PATH_MAX]; + + /** + * (read-write, borrowed) + * + * The tileset loader to use when finding tilesets in maps. + */ + struct mlk_tileset_loader *tileset_loader; + + /** \cond MLK_PRIVATE_DECLS */ + unsigned int *tiles[MLK_MAP_LAYER_TYPE_LAST]; + struct mlk_tileset tileset; + struct mlk_map_block *blocks; + /** \endcond MLK_PRIVATE_DECLS */ +}; + +/** + * Initialize the map loader. + * + * All loader member functions will be set and ::mlk_map_loader::data will be + * set to file loader. + * + * \pre file != NULL + * \pre loader != NULL + * \pre filename != NULL + * \param file the file loader + * \param loader the abstract loader interface + * \param filename path to the map file + */ +void +mlk_map_loader_file_init(struct mlk_map_loader_file *file, + struct mlk_map_loader *loader, + const char *filename); + +/** + * Cleanup allocated resources by this file loader. + * + * \pre file != NULL + * \param file the file loader + * \warning the map loaded with this loader must not be used + */ +void +mlk_map_loader_file_finish(struct mlk_map_loader_file *file); + +#endif /* !MLK_RPG_MAP_LOADER_FILE_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/mlk/rpg/map-loader.c Tue Mar 07 22:15:35 2023 +0100 @@ -0,0 +1,291 @@ +/* + * map-loader.c -- abstract map loader + * + * Copyright (c) 2020-2023 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <assert.h> +#include <errno.h> +#include <stdio.h> +#include <string.h> + +#include <mlk/util/util.h> + +#include <mlk/core/err.h> +#include <mlk/core/trace.h> +#include <mlk/core/util.h> + +#include "map-loader.h" +#include "map.h" + +static int +parse_layer_tiles(struct mlk_map_loader *loader, struct mlk_map *map, const char *layer_name, FILE *fp) +{ + enum mlk_map_layer_type layer_type; + size_t amount, current; + unsigned int *tiles; + + if (strcmp(layer_name, "background") == 0) + layer_type = MLK_MAP_LAYER_TYPE_BG; + else if (strcmp(layer_name, "foreground") == 0) + layer_type = MLK_MAP_LAYER_TYPE_FG; + else if (strcmp(layer_name, "above") == 0) + layer_type = MLK_MAP_LAYER_TYPE_ABOVE; + else + return mlk_errf("invalid layer type: %s", layer_name); + + amount = map->columns * map->rows; + current = 0; + + /* + * The next line after a layer declaration is a list of plain integer + * that fill the layer tiles. + */ + if (!(tiles = loader->alloc_tiles(loader, map, layer_type, amount))) + return -1; + + for (unsigned int tile; fscanf(fp, "%u\n", &tile) && current < amount; ++current) + tiles[current] = tile; + + map->layers[layer_type].tiles = tiles; + + return 0; +} + +static int +parse_objects(struct mlk_map_loader *loader, + struct mlk_map *map, + const char *line, + FILE *fp) +{ + (void)line; + + char fmt[64] = {0}, exec[256] = {0}; + int x = 0, y = 0, isblock = 0; + unsigned int w = 0, h = 0; + struct mlk_map_block *array, *block, *blocks = NULL; + size_t blocksz = 0; + + snprintf(fmt, sizeof (fmt), "%%d|%%d|%%u|%%u|%%d|%%%zu[^\n]\n", sizeof (exec) - 1); + + while (fscanf(fp, fmt, &x, &y, &w, &h, &isblock, exec) >= 5) { + if (!loader->load_object) { + mlk_tracef("ignoring object %d,%d,%u,%u,%d,%s", x, y, w, h, isblock, exec); + continue; + } + + loader->load_object(loader, map, x, y, w, h, exec); + + /* + * Actions do not have concept of collisions because they are + * not only used on maps. The map structure has its very own + * object to manage collisions but the .map file use the same + * directive for simplicity. So create a block region if the + * directive has one. + */ + if (isblock) { + if (!(array = loader->expand_blocks(loader, blocks, blocksz + 1))) + return -1; + + blocks = array; + block = &blocks[blocksz++]; + block->x = x; + block->y = y; + block->w = w; + block->h = h; + } + } + + /* Reference the blocks array from map_file. */ + map->blocks = blocks; + map->blocksz = blocksz; + + return 0; +} + +static int +parse_layer(struct mlk_map_loader *loader, + struct mlk_map *map, + const char *line, + FILE *fp) +{ + char fmt[32] = {0}, layer_name[32] = {0}; + + /* Check if weight/height has been specified. */ + if (map->columns == 0 || map->rows == 0) + return mlk_errf("missing map dimensions before layer"); + + /* Determine layer type. */ + snprintf(fmt, sizeof (fmt), "layer|%%%zus", sizeof (layer_name) - 1); + + if (sscanf(line, fmt, layer_name) <= 0) + return mlk_errf("missing layer type definition"); + if (strcmp(layer_name, "actions") == 0) + return parse_objects(loader, map, line, fp); + + return parse_layer_tiles(loader, map, layer_name, fp); +} + +static int +parse_tileset(struct mlk_map_loader *loader, + struct mlk_map *map, + const char *line, + FILE *fp) +{ + (void)fp; + + const char *p; + + if (!(p = strchr(line, '|'))) + return mlk_errf("could not parse tileset"); + if (!(map->tileset = loader->init_tileset(loader, map, p + 1))) + return -1; + + return 0; +} + +static int +parse_columns(struct mlk_map_loader *loader, + struct mlk_map *map, + const char *line, + FILE *fp) +{ + (void)loader; + (void)fp; + + if (sscanf(line, "columns|%u", &map->columns) != 1 || map->columns == 0) + return mlk_errf("null map columns"); + + return 0; +} + +static int +parse_rows(struct mlk_map_loader *loader, + struct mlk_map *map, + const char *line, + FILE *fp) +{ + (void)loader; + (void)fp; + + if (sscanf(line, "rows|%u", &map->rows) != 1 || map->rows == 0) + return mlk_errf("null map rows"); + + return 0; +} + +static int +parse_origin(struct mlk_map_loader *loader, + struct mlk_map *map, + const char *line, + FILE *fp) +{ + (void)loader; + (void)fp; + + if (sscanf(line, "origin|%d|%d", &map->player_x, &map->player_y) != 2) + return mlk_errf("invalid origin"); + + return 0; +} + +static int +parse_line(struct mlk_map_loader *loader, + struct mlk_map *map, + const char *line, + FILE *fp) +{ + static const struct { + const char *property; + int (*read)(struct mlk_map_loader *, struct mlk_map *, const char *, FILE *); + } props[] = { + { "columns", parse_columns }, + { "rows", parse_rows }, + { "tileset", parse_tileset }, + { "origin", parse_origin }, + { "layer", parse_layer }, + }; + + for (size_t i = 0; i < MLK_UTIL_SIZE(props); ++i) + if (strncmp(line, props[i].property, strlen(props[i].property)) == 0) + return props[i].read(loader, map, line, fp); + + return 0; +} + +static int +check(struct mlk_map *map) +{ + /* + * We don't need to check width/height because parsing layers and + * tilesets already check for their presence, so only check layers. + */ + if (!map->layers[0].tiles) + return mlk_errf("missing background layer"); + if (!map->layers[1].tiles) + return mlk_errf("missing foreground layer"); + + return 0; +} + +static int +parse(struct mlk_map_loader *loader, struct mlk_map *map, FILE *fp) +{ + char line[128]; + + while (fgets(line, sizeof (line), fp)) { + /* Remove \n if any */ + line[strcspn(line, "\r\n")] = '\0'; + + if (parse_line(loader, map, line, fp) < 0) + return -1; + } + + return check(map); +} + +int +mlk_map_loader_open(struct mlk_map_loader *loader, struct mlk_map *map, const char *path) +{ + assert(loader); + assert(map); + assert(path); + + FILE *fp; + + memset(map, 0, sizeof (*map)); + + if (!(fp = fopen(path, "r"))) + return mlk_errf("%s", strerror(errno)); + + return parse(loader, map, fp); +} + +int +mlk_map_loader_openmem(struct mlk_map_loader *loader, struct mlk_map *map, const void *data, size_t datasz) +{ + assert(loader); + assert(map); + assert(data); + + FILE *fp; + + memset(map, 0, sizeof (*map)); + + if (!(fp = mlk_util_fmemopen((void *)data, datasz, "r"))) + return -1; + + return parse(loader, map, fp); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-rpg/mlk/rpg/map-loader.h Tue Mar 07 22:15:35 2023 +0100 @@ -0,0 +1,154 @@ +/* + * map-loader.h -- abstract map loader + * + * Copyright (c) 2020-2023 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MLK_RPG_MAP_LOADER_H +#define MLK_RPG_MAP_LOADER_H + +#include <stddef.h> + +enum mlk_map_layer_type; + +struct mlk_map; +struct mlk_map_block; +struct mlk_tileset; + +/** + * \file mlk/rpg/map-loader.h + * \brief Abstract map loader + * + * This module provides a generic way to open maps. It uses a callback similar + * to the ::mlk_tileset_loader. + */ +struct mlk_map_loader { + /** + * (read-write, borrowed, optional) + * + * Arbitrary user data for callbacks. + */ + void *data; + + /** + * (read-write) + * + * Obtain a tileset that this map requires. + * + * \param self this loader + * \param map the underlying map being loaded + * \param ident the texture name (or path) + * \return the tileset to use or NULL on failure + */ + struct mlk_tileset * (*init_tileset)(struct mlk_map_loader *self, + struct mlk_map *map, + const char *ident); + + /** + * (read-write) + * + * Allocate the number of tiles required to fill a layer. + * + * \param self this loader + * \param map the underlying map being loaded + * \param type the layer type to allocate + * \param n the number of tile items (rows * columns) + * \return a pointer to a usable area or NULL on failure + */ + unsigned int * (*alloc_tiles)(struct mlk_map_loader *self, + struct mlk_map *map, + enum mlk_map_layer_type type, + size_t n); + + /** + * (read-write, optional) + * + * Load a map object from the special object layer. + * + * \param self this loader + * \param map the underlying map being loaded + * \param x the x object coordinate + * \param y the y object coordinate + * \param w the object width + * \param h the object height + * \param argument optional data to pass to the object + */ + void (*load_object)(struct mlk_map_loader *self, + struct mlk_map *map, + int x, + int y, + unsigned int w, + unsigned int h, + const char *argument); + + /** + * (read-write) + * + * Expand the array required to populate extra map collision blocks. + * + * \param self this loader + * \param map the underlying map being loaded + * \param blocks the current blocks array + * \param blocksz the number of element to *append* (not the new size) + * \return a pointer to a usable area or NULL on failure + */ + struct mlk_map_block * (*expand_blocks)(struct mlk_map_loader *self, + struct mlk_map *map, + struct mlk_map_block *blocks, + size_t blocksz); +}; + +#if defined(__cplusplus) +extern "C" { +#endif + +/** + * Try to open a map from the given path. + * + * \pre loader != NULL + * \pre map != NULL + * \pre path != NULL + * \param loader the loader interface + * \param map the map destination + * \param path the path to the map file (usually ending in .map) + * \return 0 on success or -1 on error + */ +int +mlk_map_loader_open(struct mlk_map_loader *loader, + struct mlk_map *map, + const char *path); + +/** + * Try to open a map from the given path. + * + * \pre loader != NULL + * \pre map != NULL + * \param loader the loader interface + * \param map the map destination + * \param data the map content + * \param datasz the map content length + * \return 0 on success or -1 on error + */ +int +mlk_map_loader_openmem(struct mlk_map_loader *loader, + struct mlk_map *map, + const void *data, + size_t datasz); + +#if defined(__cplusplus) +} +#endif + +#endif /* !MLK_RPG_MAP_FILE_H */
--- a/libmlk-rpg/mlk/rpg/map.c Tue Mar 07 20:58:00 2023 +0100 +++ b/libmlk-rpg/mlk/rpg/map.c Tue Mar 07 22:15:35 2023 +0100 @@ -97,8 +97,8 @@ * to check. */ static int -is_block_relevant(const struct map *map, - const struct map_block *block, +is_block_relevant(const struct mlk_map *map, + const struct mlk_map_block *block, int drow, int dcol) { @@ -130,8 +130,8 @@ * new block coordinates with the previous one. */ static int -is_block_better(const struct map_block *now, - const struct map_block *new, +is_block_better(const struct mlk_map_block *now, + const struct mlk_map_block *new, int drow, int dcol) { @@ -143,7 +143,7 @@ } static void -center(struct map *map) +center(struct mlk_map *map) { map->view_x = map->player_x - (int)(map->view_w / 2); map->view_y = map->player_y - (int)(map->view_h / 2); @@ -160,7 +160,7 @@ } static void -init(struct map *map) +init(struct mlk_map *map) { /* Adjust view. */ map->view_w = mlk_window.w; @@ -178,7 +178,7 @@ } static void -handle_keydown(struct map *map, const union mlk_event *event) +handle_keydown(struct mlk_map *map, const union mlk_event *event) { switch (event->key.key) { case MLK_KEY_UP: @@ -197,15 +197,15 @@ break; } - map->player_angle = orientations[map->player_movement]; + map->player_a = orientations[map->player_movement]; } static void -handle_keyup(struct map *map, const union mlk_event *event) +handle_keyup(struct mlk_map *map, const union mlk_event *event) { switch (event->key.key) { - case MLK_KEY_TAB: - map->flags ^= MAP_FLAGS_SHOW_GRID | MAP_FLAGS_SHOW_COLLIDE; + case MLK_KEY_F12: + map->flags ^= MLK_MAP_FLAGS_SHOW_GRID | MLK_MAP_FLAGS_SHOW_COLLIDE; break; case MLK_KEY_UP: map->player_movement &= ~(MOVING_UP); @@ -224,37 +224,39 @@ } } +// TODO: merge this code in tileset maybe. static int -cmp_tile(const struct tileset_tiledef *td1, const struct tileset_tiledef *td2) +collision_cmp(const void *d1, const void *d2) { - if (td1->id < td2->id) + const struct mlk_tileset_collision *c1 = d1; + const struct mlk_tileset_collision *c2 = d2; + + if (c1->id < c2->id) return -1; - if (td1->id > td2->id) + if (c1->id > c2->id) return 1; return 0; } -static struct tileset_tiledef * -find_tiledef_by_id(const struct map *map, unsigned short id) +static inline struct mlk_tileset_collision * +find_collision_by_id(const struct mlk_map *map, unsigned int id) { - typedef int (*cmp)(const void *, const void *); - - const struct tileset_tiledef key = { + const struct mlk_tileset_collision key = { .id = id }; - return bsearch(&key, map->tileset->tiledefs, map->tileset->tiledefsz, - sizeof (key), (cmp)cmp_tile); + return bsearch(&key, map->tileset->collisions, map->tileset->collisionsz, + sizeof (key), collision_cmp); } -static struct tileset_tiledef * -find_tiledef_by_row_column_in_layer(const struct map *map, - const struct map_layer *layer, +static struct mlk_tileset_collision * +find_collision_by_row_column_in_layer(const struct mlk_map *map, + const struct mlk_map_layer *layer, int row, int col) { - unsigned short id; + unsigned int id; if (row < 0 || (unsigned int)row >= map->rows || col < 0 || (unsigned int)col >= map->columns) @@ -263,24 +265,24 @@ if ((id = layer->tiles[col + row * map->columns]) == 0) return NULL; - return find_tiledef_by_id(map, id - 1); + return find_collision_by_id(map, id - 1); } -static struct tileset_tiledef * -find_tiledef_by_row_column(const struct map *map, int row, int col) +static struct mlk_tileset_collision * +find_collision_by_row_column(const struct mlk_map *map, int row, int col) { - struct tileset_tiledef *tile; + struct mlk_tileset_collision *tc; /* TODO: probably a for loop when we have indefinite layers. */ - if (!(tile = find_tiledef_by_row_column_in_layer(map, &map->layers[1], row, col))) - tile = find_tiledef_by_row_column_in_layer(map, &map->layers[0], row, col); + if (!(tc = find_collision_by_row_column_in_layer(map, &map->layers[1], row, col))) + tc = find_collision_by_row_column_in_layer(map, &map->layers[0], row, col); - return tile; + return tc; } static void -find_block_iterate(const struct map *map, - struct map_block *block, +find_block_iterate(const struct mlk_map *map, + struct mlk_map_block *block, int rowstart, int rowend, int colstart, @@ -291,20 +293,21 @@ assert(map); assert(block); + const struct mlk_tileset_collision *tc; + const struct mlk_map_block *b; + struct mlk_map_block tmp; + /* First, check with tiledefs. */ for (int r = rowstart; r <= rowend; ++r) { for (int c = colstart; c <= colend; ++c) { - struct tileset_tiledef *td; - struct map_block tmp; - - if (!(td = find_tiledef_by_row_column(map, r, c))) + if (!(tc = find_collision_by_row_column(map, r, c))) continue; /* Convert to absolute values. */ - tmp.x = td->x + c * map->tileset->sprite->cellw; - tmp.y = td->y + r * map->tileset->sprite->cellh; - tmp.w = td->w; - tmp.h = td->h; + tmp.x = tc->x + c * map->tileset->sprite->cellw; + tmp.y = tc->y + r * map->tileset->sprite->cellh; + tmp.w = tc->w; + tmp.h = tc->h; /* This tiledef is out of context. */ if (!is_block_relevant(map, &tmp, drow, dcol)) @@ -321,20 +324,20 @@ /* Now check if there are objects closer than tiledefs. */ for (size_t i = 0; i < map->blocksz; ++i) { - const struct map_block *new = &map->blocks[i]; + b = &map->blocks[i]; - if (is_block_relevant(map, new, drow, dcol) && - is_block_better(block, new, drow, dcol)) { - block->x = new->x; - block->y = new->y; - block->w = new->w; - block->h = new->h; + if (is_block_relevant(map, b, drow, dcol) && + is_block_better(block, b, drow, dcol)) { + block->x = b->x; + block->y = b->y; + block->w = b->w; + block->h = b->h; } } } static void -find_collision(const struct map *map, struct map_block *block, int drow, int dcolumn) +find_collision(const struct mlk_map *map, struct mlk_map_block *block, int drow, int dcolumn) { assert((drow && !dcolumn) || (dcolumn && !drow)); @@ -386,9 +389,9 @@ } static void -move_x(struct map *map, int delta) +move_x(struct mlk_map *map, int delta) { - struct map_block block; + struct mlk_map_block block; find_collision(map, &block, 0, delta < 0 ? -1 : +1); @@ -410,9 +413,9 @@ } static void -move_y(struct map *map, int delta) +move_y(struct mlk_map *map, int delta) { - struct map_block block; + struct mlk_map_block block; find_collision(map, &block, delta < 0 ? -1 : +1, 0); @@ -434,7 +437,7 @@ } static void -move(struct map *map, unsigned int ticks) +move(struct mlk_map *map, unsigned int ticks) { /* This is the amount of pixels the player must move. */ const int delta = SPEED * ticks / SEC; @@ -468,8 +471,8 @@ } static inline void -draw_layer_tile(const struct map *map, - const struct map_layer *layer, +draw_layer_tile(const struct mlk_map *map, + const struct mlk_map_layer *layer, struct mlk_texture *colbox, int start_col, int start_row, @@ -478,7 +481,7 @@ unsigned int r, unsigned int c) { - const struct tileset_tiledef *td; + const struct mlk_tileset_collision *tc; int index, id, sc, sr, mx, my; index = (start_col + c) + ((start_row + r) * map->columns); @@ -496,12 +499,13 @@ mx = start_x + (int)c * (int)map->tileset->sprite->cellw; my = start_y + (int)r * (int)map->tileset->sprite->cellh; - tileset_draw(map->tileset, sr, sc, mx, my); + mlk_tileset_draw(map->tileset, sr, sc, mx, my); - if ((td = find_tiledef_by_id(map, id)) && mlk_texture_ok(colbox)) - mlk_texture_scale(colbox, 0, 0, 5, 5, mx + td->x, my + td->y, td->w, td->h, 0); + /* Draw collision box if colbox is non NULL. */ + if ((tc = find_collision_by_id(map, id)) && mlk_texture_ok(colbox)) + mlk_texture_scale(colbox, 0, 0, 5, 5, mx + tc->x, my + tc->y, tc->w, tc->h, 0); - if (map->flags & MAP_FLAGS_SHOW_GRID) { + if (map->flags & MLK_MAP_FLAGS_SHOW_GRID) { mlk_painter_set_color(0x202e37ff); mlk_painter_draw_line(mx, my, mx + (int)map->tileset->sprite->cellw, my); mlk_painter_draw_line( @@ -511,7 +515,7 @@ } static void -draw_layer(const struct map *map, const struct map_layer *layer) +draw_layer(const struct mlk_map *map, const struct mlk_map_layer *layer) { assert(map); assert(layer); @@ -534,7 +538,7 @@ return; /* Show collision box if requested. */ - if (map->flags & MAP_FLAGS_SHOW_COLLIDE && mlk_texture_new(&colbox, 16, 16) == 0) { + if (map->flags & MLK_MAP_FLAGS_SHOW_COLLIDE && mlk_texture_new(&colbox, 16, 16) == 0) { mlk_texture_set_blend_mode(&colbox, MLK_TEXTURE_BLEND_BLEND); mlk_texture_set_alpha_mod(&colbox, 100); MLK_PAINTER_BEGIN(&colbox); @@ -557,11 +561,11 @@ } static void -draw_collide(const struct map *map) +draw_collide(const struct mlk_map *map) { struct mlk_texture box = {0}; - if (map->flags & MAP_FLAGS_SHOW_COLLIDE && mlk_texture_new(&box, 64, 64) == 0) { + if (map->flags & MLK_MAP_FLAGS_SHOW_COLLIDE && mlk_texture_new(&box, 64, 64) == 0) { /* Draw collide box around player if requested. */ mlk_texture_set_alpha_mod(&box, 100); mlk_texture_set_blend_mode(&box, MLK_TEXTURE_BLEND_BLEND); @@ -591,18 +595,18 @@ } int -map_init(struct map *map) +mlk_map_init(struct mlk_map *map) { assert(map); init(map); - tileset_start(map->tileset); + mlk_tileset_start(map->tileset); return 0; } void -map_handle(struct map *map, const union mlk_event *ev) +mlk_map_handle(struct mlk_map *map, const union mlk_event *ev) { assert(map); assert(ev); @@ -617,55 +621,38 @@ default: break; } - - mlk_action_stack_handle(&map->astack_par, ev); - mlk_action_stack_handle(&map->astack_seq, ev); } void -map_update(struct map *map, unsigned int ticks) +mlk_map_update(struct mlk_map *map, unsigned int ticks) { assert(map); - mlk_action_stack_update(&map->astack_par, ticks); - mlk_action_stack_update(&map->astack_seq, ticks); - - tileset_update(map->tileset, ticks); - - /* No movements if the sequential actions are running. */ - if (mlk_action_stack_completed(&map->astack_seq)) - move(map, ticks); + mlk_tileset_update(map->tileset, ticks); + move(map, ticks); } void -map_draw(const struct map *map) +mlk_map_draw(const struct mlk_map *map) { assert(map); /* Draw the texture about background/foreground. */ - draw_layer(map, &map->layers[MAP_LAYER_TYPE_BACKGROUND]); - draw_layer(map, &map->layers[MAP_LAYER_TYPE_FOREGROUND]); + draw_layer(map, &map->layers[MLK_MAP_LAYER_TYPE_BG]); + draw_layer(map, &map->layers[MLK_MAP_LAYER_TYPE_FG]); walksprite_draw( &map->player_ws, - map->player_angle, + map->player_a, map->player_x - map->view_x, map->player_y - map->view_y); - draw_layer(map, &map->layers[MAP_LAYER_TYPE_ABOVE]); + draw_layer(map, &map->layers[MLK_MAP_LAYER_TYPE_ABOVE]); draw_collide(map); - - mlk_action_stack_draw(&map->astack_par); - mlk_action_stack_draw(&map->astack_seq); } void -map_finish(struct map *map) +mlk_map_finish(struct mlk_map *map) { assert(map); - - mlk_action_stack_finish(&map->astack_par); - mlk_action_stack_finish(&map->astack_seq); - - memset(map, 0, sizeof (*map)); }
--- a/libmlk-rpg/mlk/rpg/map.h Tue Mar 07 20:58:00 2023 +0100 +++ b/libmlk-rpg/mlk/rpg/map.h Tue Mar 07 22:15:35 2023 +0100 @@ -21,100 +21,103 @@ #include <stddef.h> -#include <mlk/core/action.h> -#include <mlk/core/action-stack.h> - #include "walksprite.h" -struct tileset; +struct mlk_map; +struct mlk_tileset; union mlk_event; -enum map_layer_type { - MAP_LAYER_TYPE_BACKGROUND, - MAP_LAYER_TYPE_FOREGROUND, - MAP_LAYER_TYPE_ABOVE, - MAP_LAYER_TYPE_NUM +enum mlk_map_layer_type { + MLK_MAP_LAYER_TYPE_BG, + MLK_MAP_LAYER_TYPE_FG, + MLK_MAP_LAYER_TYPE_ABOVE, + MLK_MAP_LAYER_TYPE_LAST }; -struct map_layer { - unsigned short *tiles; +struct mlk_map_layer { + unsigned int *tiles; }; -enum map_flags { - MAP_FLAGS_NONE = 0, - MAP_FLAGS_SHOW_GRID = (1 << 0), - MAP_FLAGS_SHOW_COLLIDE = (1 << 2) +enum mlk_map_flags { + MLK_MAP_FLAGS_NONE = 0, + MLK_MAP_FLAGS_SHOW_GRID = (1 << 0), + MLK_MAP_FLAGS_SHOW_COLLIDE = (1 << 2) }; -struct map_block { +struct mlk_map_block { int x; int y; unsigned int w; unsigned int h; }; -struct map { - const char *title; /*!< (+) Map title name. */ - unsigned int columns; /*!< (-) Number of columns. */ - unsigned int rows; /*!< (-) Number of rows. */ +struct mlk_map_style { + unsigned long grid_color; + unsigned long collision_color; +}; - /* Tileset. */ - struct tileset *tileset; /*!< (+&?) Tileset to use. */ +struct mlk_map_delegate { + void *data; + void (*update)(struct mlk_map_delegate *self, struct mlk_map *map, unsigned int ticks); + void (*draw)(struct mlk_map_delegate *self, const struct mlk_map *map); +}; - /* View options. */ - enum map_flags flags; /*!< (+) View options. */ +struct mlk_map { + unsigned int columns; + unsigned int rows; - /* Extra collisions blocks. */ - struct map_block *blocks; /*!< (+&?) Extra collisions. */ - size_t blocksz; /*!< (+) Number of collisions. */ + struct mlk_tileset *tileset; - /* List of actions. */ - struct mlk_action_stack astack_par; /*!< (+) Parallel actions. */ - struct mlk_action_stack astack_seq; /*!< (+) Blocking actions. */ + enum mlk_map_flags flags; + + const struct mlk_map_block *blocks; + size_t blocksz; - /* Player. */ - struct mlk_sprite *player_sprite; /*!< (+) The sprite to use */ - struct walksprite player_ws; /*!< (-) Walking sprite for moving the player. */ - int player_x; /*!< (+) Player position in x */ - int player_y; /*!< (+) Player position in y */ - int player_angle; /*!< (+) Player angle (see walksprite) */ - unsigned int player_movement; /*!< (*) Current player movements. */ + struct mlk_sprite *player_sprite; + int player_x; + int player_y; + int player_a; + unsigned int player_movement; + struct walksprite player_ws; + + int view_x; + int view_y; + unsigned int view_w; + unsigned int view_h; - /* View to zoom/locate. */ - int view_x; /*!< (+) Position in x */ - int view_y; /*!< (+) Position in y */ - unsigned int view_w; /*!< (+) View width */ - unsigned int view_h; /*!< (+) View height */ + int margin_x; + int margin_y; + unsigned int margin_w; + unsigned int margin_h; + + struct mlk_map_layer layers[MLK_MAP_LAYER_TYPE_LAST]; - /* View margin. */ - int margin_x; /*!< (+) View margin in x. */ - int margin_y; /*!< (+) View margin in y. */ - unsigned int margin_w; /*!< (+) Margin width. */ - unsigned int margin_h; /*!< (+) Margin height. */ + struct mlk_button_style *style; + struct mlk_button_delegate *delegate; +}; - /* Different tile layers. */ - struct map_layer layers[MAP_LAYER_TYPE_NUM]; -}; +extern struct mlk_map_style mlk_map_style; +extern struct mlk_map_delegate mlk_map_delegate; #if defined(__cplusplus) extern "C" { #endif int -map_init(struct map *map); +mlk_map_init(struct mlk_map *map); void -map_handle(struct map *map, const union mlk_event *ev); +mlk_map_handle(struct mlk_map *map, const union mlk_event *ev); void -map_update(struct map *map, unsigned int ticks); +mlk_map_update(struct mlk_map *map, unsigned int ticks); void -map_draw(const struct map *map); +mlk_map_draw(const struct mlk_map *map); void -map_finish(struct map *map); +mlk_map_finish(struct mlk_map *map); #if defined(__cplusplus) }
--- a/libmlk-rpg/mlk/rpg/tileset-loader-file.h Tue Mar 07 20:58:00 2023 +0100 +++ b/libmlk-rpg/mlk/rpg/tileset-loader-file.h Tue Mar 07 22:15:35 2023 +0100 @@ -61,6 +61,10 @@ /** \endcond MLK_PRIVATE_DECLS */ }; +#if defined(__cplusplus) +extern "C" { +#endif + /** * Fill the abstract loader with appropriate implementation. * @@ -90,4 +94,8 @@ void mlk_tileset_loader_file_finish(struct mlk_tileset_loader_file *file); +#if defined(__cplusplus) +} +#endif + #endif /* !MLK_RPG_TILESET_LOADER_FILE_H */
--- a/libmlk-rpg/mlk/rpg/tileset-loader.c Tue Mar 07 20:58:00 2023 +0100 +++ b/libmlk-rpg/mlk/rpg/tileset-loader.c Tue Mar 07 22:15:35 2023 +0100 @@ -146,7 +146,7 @@ size_t tileanimationsz = 0; /* Create a format string for fscanf. */ - snprintf(fmt, sizeof (fmt), "%%u|%%%zu[^|]|%%u", sizeof (filename)); + snprintf(fmt, sizeof (fmt), "%%u|%%%zu[^|]|%%u", sizeof (filename) - 1); /* * When parsing animations, we have to create three different
--- a/libmlk-rpg/mlk/rpg/tileset-loader.h Tue Mar 07 20:58:00 2023 +0100 +++ b/libmlk-rpg/mlk/rpg/tileset-loader.h Tue Mar 07 22:15:35 2023 +0100 @@ -133,6 +133,8 @@ * Open a tileset from a filesystem path. * * \pre loader != NULL + * \pre tileset != NULL + * \pre data != NULL * \param loader the loader * \param tileset the tileset destination * \param path the path to the tileset file @@ -150,6 +152,8 @@ * used. * * \pre loader != NULL + * \pre tileset != NULL + * \pre data != NULL * \param loader the loader * \param tileset the tileset destination * \param data the tileset content
--- a/mlk-map/mlk-map.c Tue Mar 07 20:58:00 2023 +0100 +++ b/mlk-map/mlk-map.c Tue Mar 07 22:15:35 2023 +0100 @@ -212,8 +212,7 @@ static void write_tileset(const json_t *tilesets) { - char path[MLK_PATH_MAX]; - char filename[FILENAME_MAX] = {0}, *ext; + char path[MLK_PATH_MAX], *ext; const json_t *tileset, *source; if (json_array_size(tilesets) != 1) @@ -227,14 +226,13 @@ /* We need to replace the .json extension to .tileset. */ snprintf(path, sizeof (path), "%s", json_string_value(source)); - snprintf(filename, sizeof (filename), "%s", mlk_util_basename(path)); - if (!(ext = strstr(filename, ".json"))) + if (!(ext = strstr(path, ".json"))) die("could not determine tileset extension"); *ext = '\0'; - printf("tileset|%s.tileset\n", filename); + printf("tileset|%s.tileset\n", path); } int