123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453 |
- // #include <mxml.h>
- #include "mem.h"
- #include "image.h"
- #include "tilemap.h"
- #include "dynar.h"
- #include "monolog.h"
- /* Hide tiles for debuggging, or not. */
- #ifdef ERUTA_NOGFX_MODE
- #define TILEMAP_NO_TILES
- #endif
- /** A tile map is a game map, roughly equivalent to a "level" that uses tiled
- * panes for it's display. It also contains an Area for the physical, logical
- * and graphical representation of in-game objects.
- * The plan is to have an area per tile map and copy the player characters between
- * those areas when moved, but keeping their ID's the same.
- * This should make keeping track of the characters (from scripting, etc) easier.
- */
- struct Tilemap_ {
- Image * texture;
- int textureid;
- int gridw;
- int gridh;
- Tileset * set;
- Dynar * panes;
- Area * area;
- };
- #define TEXTURE_TILE "tile"
- #define TEXTURE_PLAYER "play"
- #define TEXTURE_GEAR "gear"
- #define TEXTURE_WEAPON "arms"
- #define TEXTURE_FOE "foes"
- #define TEXTURE_ITEM "item"
- /** Loads an image of the given category and index as a texture. */
- Image * image_loadtexture(const char * category, int index) {
- char buf[1024];
- Image * image;
- sprintf(buf, "data/image/%s_%03d.png", category, index);
- image = image_load(buf);
- return image;
- }
- /** Cleans up a tilemap. */
- Tilemap * tilemap_done(Tilemap * self) {
- int index;
- if(!self) return NULL;
- for(index = 0; index < TILEMAP_PANES; index++) {
- tilepane_free(dynar_getptr(self->panes, index));
- }
- dynar_free(self->panes);
- tileset_free(self->set);
- /* the area is not owned so we don't free that */
- // tilemap_initempty(self);
- return self;
- }
- /** Initializes a tile map */
- Tilemap* tilemap_init(Tilemap * self, Tileset * set, int w, int h, Area * unused__) {
- int index;
-
- (void) unused__;
- if(!self) return NULL;
- self->gridw = w;
- self->gridh = h;
- self->set = set;
- if(!self->set) { return NULL; }
- self->panes = dynar_new(TILEMAP_PANES, sizeof(Tilepane *));
- if(!self->panes) { return NULL; }
- for(index = 0; index < TILEMAP_PANES; index++) {
- dynar_putptr(self->panes, index, NULL);
- }
- return self;
- }
- /** Frees the tile map and initializes it. */
- Tilemap * tilemap_free(Tilemap * map) {
- tilemap_done(map);
- mem_free(map);
- return NULL;
- }
- /** Allocates a new tile map and initializes it. */
- Tilemap * tilemap_new(Tileset * set, int w, int h, Area * unused__ ) {
- Tilemap * map = STRUCT_ALLOC(Tilemap);
- (void) unused__;
- if(!tilemap_init(map, set, w, h, NULL)) {
- return tilemap_free(map);
- }
- return map;
- }
- /** Returns a pointer to the pane at index or NULL if out of range. */
- Tilepane * tilemap_pane(Tilemap * self, int index) {
- return dynar_getptr(self->panes, index);
- }
- /** Sets a new tile pane for the pane at indexeth index of the tile map.
- * the old pane, if any, will be deleted with tilepane_free
- */
- Tilepane * tilemap_pane_(Tilemap * self, int index, Tilepane * pane) {
- Tilepane * oldpane;
- oldpane = tilemap_pane(self, index);
- // Replace old pane, so free it.
- tilepane_free(oldpane);
- dynar_putptr(self->panes, index, pane);
- return pane;
- }
- /** Makes a new tile pane for the pane at indexeth index of the tile map. */
- Tilepane * tilemap_panenew(Tilemap * self, int index, int w, int h) {
- Tilepane * pane = tilepane_new(self->set, w, h);
- return tilemap_pane_(self, index, pane);
- }
- /** Returns the tile in the tile map in the given layer at the given tile coords. */
- Tile * tilemap_get(Tilemap * self, int l, int x, int y) {
- Tilepane * pane = tilemap_pane(self, l);
- if(!pane) return NULL;
- return tilepane_get(pane, x, y);
- }
- /** Converts the tile's flags to an integer id for the best Thing to
- represent this tile. Returns THING_UNUSED if it needs no physical representation. */
- int tile_thingkind(Tile * tile) {
- if (!tile) return THING_UNUSED;
- if (tile_index(tile)<1) return THING_UNUSED;
- if (tile_isflag(tile, TILE_WALL)) return THING_WALL;
- if (tile_isflag(tile, TILE_STAIR)) return THING_STAIR;
- if (tile_isflag(tile, TILE_WATER)) return THING_WATER;
- return THING_UNUSED;
- }
- /** Sets a tile in the tile map to the given tile. */
- Tile * tilemap_settile(Tilemap * self, int l, int x, int y, Tile * tile) {
- Tile * aidt = NULL;
- Tilepane * pane = tilemap_pane(self, l);
- if(!pane) return NULL;
- aidt = tilepane_set(pane, x, y, tile);
- if(!aidt) return NULL;
- return tile;
- }
- /** Sets a tile in the tile map to the tile with the given index. */
- Tile * tilemap_setindex(Tilemap * self, int l, int x, int y, int index) {
- Tilepane * pane = tilemap_pane(self, l);
- Tile * tile = NULL;
- if(!pane) return NULL;
- tile = tilepane_setindex(pane, x, y, index);
- if(!tile) return NULL;
- return tile;
- }
- /** Sets a rectangle area in the tile map to the given tile. */
- Tile * tilemap_rect(Tilemap * self, int l,
- int x, int y, int w, int h, Tile * tile) {
- Tilepane * pane = tilemap_pane(self, l);
- if(!pane) return NULL;
- return tilepane_rect(pane, x, y, w, h, tile);
- }
- /** Sets a rectangle area in the tile map to the given tile. */
- Tile * tilemap_fill(Tilemap * self, int l, Tile * tile) {
- Tilepane * pane = tilemap_pane(self, l);
- return tilepane_fill(pane, tile);
- }
- /** Gets the index of the tile at the given location in the tilemap. */
- int tilemap_getindex(Tilemap * self, int l, int x, int y) {
- Tilepane * pane = tilemap_pane(self, l);
- return (int) tilepane_getindex(pane, x, y);
- }
- /** Sets the drawing flags of the tile at (x, y) in layer l. */
- int tilemap_set_flags(Tilemap * self, int l, int x, int y, int flags) {
- Tilepane * pane = tilemap_pane(self, l);
- if (!pane) return -1;
- return tilepane_set_flags(pane, x, y, flags);
- }
- /** Gets the drawing flags of the tile at (x, y) in layer l. */
- int tilemap_get_flags(Tilemap * self, int l, int x, int y) {
- Tilepane * pane = tilemap_pane(self, l);
- if (!pane) return -1;
- return tilepane_get_flags(pane, x, y);
- }
- /** Draws a tile map. */
- void tilemap_draw(Tilemap * map, Camera * camera) {
- int index;
- Tilepane * pane;
- Tilepane * floor = NULL;
- /* XXX the blends and the shadows don't mix well, perhaps draw shadows
- * first???
- */
- for(index = 0; index < TILEMAP_PANES; index++) {
- pane = tilemap_pane(map, index);
- if (pane) {
- tilepane_draw(pane, camera);
- if (index == 0) {
- tilepane_draw_blends(pane, camera);
- floor = pane;
- } else if (index > 0) {
- tilepane_draw_shadows_of(pane, floor, camera);
- }
- } else {
- LOG_WARNING("Pane missing: %d", index);
- }
- }
- }
- /** Draws a layer in the tile map with the given index,
- without blends nor shadows. */
- void tilemap_draw_layer_tiles(Tilemap * map, Camera * camera, int layer) {
- Tilepane * pane;
- pane = tilemap_pane(map, layer);
- if (pane) {
- tilepane_draw(pane, camera);
- }
- }
- /** Draws the blends in a layer in the tile map with the given index,
- if it exists. Otherwise does nothing. */
- void tilemap_draw_layer_blends(Tilemap * map, Camera * camera, int layer) {
- Tilepane * pane;
- pane = tilemap_pane(map, layer);
- if (pane) {
- tilepane_draw_blends(pane, camera);
- }
- }
- /** Draws the shadows a given layer in a tile map casts if it exists
- * and isn't equal to 0.
- * Otherwise does nothing. */
- void tilemap_draw_layer_shadows(Tilemap * map, Camera * camera, int layer) {
- Tilepane * pane;
- Tilepane * floor;
- if (layer < 1) return ;
- pane = tilemap_pane(map, layer);
- if (!pane) return;
- floor = tilemap_pane(map, layer-1);
- tilepane_draw_shadows_of(pane, floor, camera);
- }
- /** Draws a layer in the tile map with the given index,
- if it exists. Otherwise does nothing. */
- void tilemap_draw_layer(Tilemap * map, Camera * camera, int layer) {
- /* Shadows must be drawn before blends otherwise both won't look good. */
- tilemap_draw_layer_tiles( map, camera, layer);
- tilemap_draw_layer_shadows( map, camera, layer);
- tilemap_draw_layer_blends( map, camera, layer);
- }
- /** Updates the tile map. Currently this animates the tiles. */
- void tilemap_update(Tilemap * map, double dt) {
- tileset_update(map->set, dt);
- }
- /** Adds a dynamic thing of the given type to the tile map's area */
- Thing * tilemap_addthing(Tilemap * self, int index, int kind, int x, int y, int z,
- int w, int h) {
- /** XXX this will be hard to find back from the scripting side, fix this! */
- return area_new_thing(self->area, kind, x, y, z, w, h);
- }
- /** Sets up the camera so it will stay locked in to the
- given layer of the tile map */
- Lockin * tilepane_lockin(Tilepane * pane, Camera * camera) {
- float x, y, w, h;
- if(!pane) return NULL;
- x = 0.0;
- y = 0.0;
- w = tilepane_wide(pane);
- h = tilepane_high(pane);
- return camera_newlockin(camera, x, y, w, h);
- }
- /** Sets up the camera so it will stay locked in to the
- extent of the given layer of the tile map. */
- Lockin * tilemap_layer_lockin(Tilemap * map,
- int layer,
- Camera * camera) {
- Tilepane * pane;
- Lockin * result;
- float x, y, w, h;
- if (!map) return NULL;
- pane = tilemap_pane(map, layer);
- return tilepane_lockin(pane, camera);
- }
- /* Returns the tile map's area. */
- Area * tilemap_area(Tilemap * self) {
- if(!self) return NULL;
- return self->area;
- }
- /* Returns a thing from this tile map's area. */
- Thing * tilemap_thing(Tilemap * self, int index) {
- Area * area = tilemap_area(self);
- return area_thing(area, index);
- }
- /* Gets the map's grid size from the largest tile layer */
- int tilemap_gridwide(Tilemap * self) {
- int wide = 0;
- int index;
- for (index = 0; index < TILEMAP_PANES; index++) {
- int aid = tilepane_gridwide(tilemap_pane(self, index));
- if (aid > wide) {
- wide = aid;
- }
- }
- return wide;
- }
- /* Gets the map's grid size from the largest tile layer */
- int tilemap_gridhigh(Tilemap * self) {
- int high = 0;
- int index;
- for (index = 0; index < TILEMAP_PANES; index++) {
- int aid = tilepane_gridhigh(tilemap_pane(self, index));
- if (aid > high) {
- high = aid;
- }
- }
- return high;
- }
- /** Returns the almount of tile panes in this map. */
- int tilemap_panes(Tilemap * self) {
- (void) self;
- return TILEMAP_PANES;
- }
- /** Sets up automatic blending for this tile map. This is called automatically
- after loading the Tilemap */
- bool tilemap_init_blend(Tilemap * self) {
- bool res = true;
- bool aid;
- int index;
- for (index = 0; index < TILEMAP_PANES; index++) {
- aid = tilepane_init_blend(tilemap_pane(self, index), index);
- res = aid && res;
- }
- return res;
- }
- /* Returns the tileset used for this tile map. */
- Tileset * tilemap_tileset(Tilemap * me) {
- if (!me) return NULL;
- return me->set;
- }
- /** Returns the firstgid for the tileset of this map,
- * or negative on error */
- /* Returns the tileset used for this tile map. */
- int tilemap_firstgid(Tilemap * me) {
- Tileset * set = tilemap_tileset(me);
- if (!set) return -1;
- return tileset_firstgid(set);
- }
- #ifdef SEPARATE_TILEMAP_LOADER
- /* Amount of tilemaps that can be loaded at oce. */
- #ifndef ERUTA_TILEMAPS_MAX
- #define ERUTA_TILEMAPS_MAX 16
- #endif
- /* "Globally" loaded tile maps. Allow up to ERUTA_TILEMAPS_MAX tile maps to be
- * loaded at the same time. */
- static Tilemap * tilemaps[ERUTA_TILEMAPS_MAX];
- static int active_tilemap = -1;
- /* Currently active tile map, if any. Negative means, none active. */
- int tilemaps_max(void) {
- return ERUTA_TILEMAPS_MAX;
- }
- int tilemaps_out_of_bounds(int index) {
- if (index < 0) return TRUE;
- if (index >tilemaps_max()) return TRUE;
- return false;
- }
- Tilemap * tilemaps_put_raw(int index, Tilemap * map) {
- if(tilemaps_out_of_bounds(index)) return NULL;
- return tilemaps[index] = map;
- }
- /* Puts map at index, unloading any previously loaded map. */
- Tilemap * tilemaps_put(int index, Tilemap * map) {
- if(tilemaps_out_of_bounds(index)) return NULL;
- if(tilemaps[index]) tilemap_free(tilemaps[index]);
- return tilemaps[index] = map;
- }
- int tilemaps_init(void) {
- int index;
- for(index = 0; index < tilemaps_max(); index ++) {
- tilemaps_put_raw(index, NULL);
- }
- }
- Tilemap * tilemaps_get(int index) {
- if(tilemaps_out_of_bounds(index)) return NULL;
- return tilemaps[index];
- }
- /* Deallocates all loaded tile maps. */
- int tilemaps_done(void) {
- int index;
- for(index = 0; index < tilemaps_max(); index ++) {
- tilemaps_put(index, NULL);
- }
- }
- #endif
|