Mercurial > molko
view librpg/rpg/map.c @ 192:4ad7420ab678
rpg: add minimalist battle system, continue #2477 @60h
- Implement battle as states,
- Add basic support for spells (no calculation yet),
- Add won/lost state,
- Add animations and messages,
- Add order.
author | David Demelier <markand@malikania.fr> |
---|---|
date | Sat, 07 Nov 2020 16:00:39 +0100 |
parents | eb0a7ab71023 |
children | 852d0b7817ce |
line wrap: on
line source
/* * map.c -- game map * * Copyright (c) 2020 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 <stdlib.h> #include <string.h> #include <core/error.h> #include <core/image.h> #include <core/painter.h> #include <core/sprite.h> #include <core/sys.h> #include <core/texture.h> #include <core/window.h> #include "map.h" /* Create %<v>c string literal for scanf */ #define MAX_F(v) MAX_F_(v) #define MAX_F_(v) "%" #v "c" static void parse_layer(struct map_data *data, const char *line, FILE *fp) { char layer_name[32 + 1] = { 0 }; struct map_layer *layer; size_t amount, current; /* Determine layer. */ if (sscanf(line, "layer|%32s", layer_name) <= 0) return; if (strcmp(layer_name, "background") == 0) layer = &data->layers[0]; else if (strcmp(layer_name, "foreground") == 0) layer = &data->layers[1]; else return; /* Check if weight/height has been specified. */ if (data->w == 0 || data->h == 0) return; amount = data->w * data->h; current = 0; if (!(layer->tiles = calloc(amount, sizeof (unsigned short)))) return; for (int tile; fscanf(fp, "%d", &tile) && current < amount; ++current) layer->tiles[current] = tile; } static void parse(struct map_data *data, const char *line, FILE *fp) { if (strncmp(line, "title", 5) == 0) sscanf(line, "title|" MAX_F(MAP_TITLE_MAX), data->title); else if (strncmp(line, "width", 5) == 0) sscanf(line, "width|%u", &data->w); else if (strncmp(line, "height", 6) == 0) sscanf(line, "height|%u", &data->h); else if (strncmp(line, "tilewidth", 9) == 0) sscanf(line, "tilewidth|%hu", &data->tile_w); else if (strncmp(line, "tileheight", 10) == 0) sscanf(line, "tileheight|%hu", &data->tile_h); else if (strncmp(line, "origin", 6) == 0) sscanf(line, "origin|%d|%d", &data->origin_x, &data->origin_y); else if (strncmp(line, "tileset", 7) == 0) sscanf(line, "tileset|" MAX_F(MAP_TILESET_MAX), data->tileset); else if (strncmp(line, "layer", 5) == 0) parse_layer(data, line, fp); } static bool check(struct map_data *data) { if (strlen(data->title) == 0) return errorf("data has no title"); if (data->w == 0 || data->h == 0) return errorf("data has null sizes"); if (data->tile_w == 0 || data->tile_h == 0) return errorf("data has null tile sizes"); if (!data->layers[0].tiles || !data->layers[1].tiles) return errorf("could not allocate data"); return true; } static void draw_layer(struct map *map, const struct map_layer *layer) { assert(map); assert(layer); struct sprite sprite; int x = 0, y = 0; sprite_init(&sprite, map->tileset, map->data->tile_w, map->data->tile_h); for (unsigned int r = 0; r < map->data->w; ++r) { for (unsigned int c = 0; c < map->data->h; ++c) { unsigned int si = r * map->data->w + c; unsigned int sr = (layer->tiles[si] - 1) / sprite.ncols; unsigned int sc = (layer->tiles[si] - 1) % sprite.nrows; if (layer->tiles[si] != 0) sprite_draw(&sprite, sr, sc, x, y); x += map->data->tile_w; } x = 0; y += map->data->tile_h; } } bool map_data_open_fp(struct map_data *data, FILE *fp) { assert(data); char line[1024]; if (!fp) return false; memset(data, 0, sizeof (*data)); while (fgets(line, sizeof (line), fp)) { /* Remove \n if any */ line[strcspn(line, "\n")] = '\0'; parse(data, line, fp); } fclose(fp); if (!check(data)) { map_data_finish(data); return false; } /* Compute real size. */ data->real_w = data->w * data->tile_w; data->real_h = data->h * data->tile_h; return true; } bool map_data_open(struct map_data *data, const char *path) { assert(data); assert(path); return map_data_open_fp(data, fopen(path, "r")); } bool map_data_openmem(struct map_data *data, const void *buf, size_t bufsz) { assert(data); assert(buf); return map_data_open_fp(data, fmemopen((void *)buf, bufsz, "r")); } void map_data_finish(struct map_data *data) { assert(data); free(data->layers[0].tiles); free(data->layers[1].tiles); memset(data, 0, sizeof (*data)); } bool map_init(struct map *map, struct map_data *data, struct texture *tileset) { assert(map); assert(data); assert(tileset && texture_ok(tileset)); if (!(texture_new(&map->picture, data->real_w, data->real_h))) return false; map->data = data; map->tileset = tileset; map_repaint(map); return true; } void map_draw(struct map *map, int srcx, int srcy) { texture_scale(&map->picture, srcx, srcy, window.w, window.h, 0, 0, window.w, window.h, 0.0); } void map_repaint(struct map *map) { PAINTER_BEGIN(&map->picture); draw_layer(map, &map->data->layers[0]); draw_layer(map, &map->data->layers[1]); PAINTER_END(); } void map_finish(struct map *map) { assert(map); texture_finish(&map->picture); memset(map, 0, sizeof (*map)); }