//--- // map: Dynamic level models // // This module provides dynamic maps as they are used during games. This // includes objects being activated and their current state, doors being // opened, crates being blown up, you name it. But not moving entities. //--- #pragma once #include "fixed.h" #include "map.h" #include "geometry.h" #include #include #include #include //--- // Tileset //--- typedef struct { /* Rendering plane */ uint8_t plane; /* Length of animation cycle. This is only defined for the first tile of each cycle, because the cycle can use the same tile several times. If anim_length=0 there is no animation; anim_length=1 is useless. */ uint8_t anim_length; /* Index in the tileset's animation array where this tile's animation cycle starts; it spans the range [anim_start .. anim_start+anim_length). */ uint8_t anim_start; /* Hitbox. TODO: Allow any collision rectangle for tiles, for decor */ bool solid; } tile_info_t; typedef struct { /* ID of the tile visible during this frame */ uint16_t tile_id; /* Duration before next frame, in ms */ uint16_t duration_ms; } tile_animation_frame_t; typedef struct { int width, height; bopti_image_t const *sheet; /* Tile information */ tile_info_t *tiles; /* Animations */ tile_animation_frame_t *anim; } tileset_t; /* Shape for a tile; this lives in a coordinate system whose (0,0) ends up at the middle of the tile in the map space (which is a point with half-integer coordinates) */ rect tile_shape(tileset_t const *tileset, int id); //--- // Tiles //--- typedef struct { /* Base layer: floor/wall pattern */ uint8_t base; /* Decoration layer */ uint8_t decor; } map_cell_t; //--- // Map grid, tiles location in space, and entities //--- typedef struct { /* Dimensions, columns are 0 to width-1, rows are 0 to height-1 */ uint16_t width, height; /* Tileset base (first layer), tileset decor (second layer) */ tileset_t *tileset; /* All cells */ map_cell_t *cells; } map_t; /* Get a pointer to the cell at (x,y) in map; NULL if out of bounds. */ map_cell_t *map_cell(map_t const *m, int x, int y); /* Check whether a map cell is walkable, only accounting for full hitboxes. */ bool map_cell_walkable(map_t const *m, map_cell_t const *cell); /* Check whether a hitbox collides with the map. */ bool map_collides(map_t const *m, rect hitbox); /* Returns the new position of an object with a hitbox trying to move from [old_pos] to [new_pos]. */ vec2 map_move(map_t const *m, vec2 old_pos, vec2 new_pos, rect hitbox);