tilemap.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453
  1. // #include <mxml.h>
  2. #include "mem.h"
  3. #include "image.h"
  4. #include "tilemap.h"
  5. #include "dynar.h"
  6. #include "monolog.h"
  7. /* Hide tiles for debuggging, or not. */
  8. #ifdef ERUTA_NOGFX_MODE
  9. #define TILEMAP_NO_TILES
  10. #endif
  11. /** A tile map is a game map, roughly equivalent to a "level" that uses tiled
  12. * panes for it's display. It also contains an Area for the physical, logical
  13. * and graphical representation of in-game objects.
  14. * The plan is to have an area per tile map and copy the player characters between
  15. * those areas when moved, but keeping their ID's the same.
  16. * This should make keeping track of the characters (from scripting, etc) easier.
  17. */
  18. struct Tilemap_ {
  19. Image * texture;
  20. int textureid;
  21. int gridw;
  22. int gridh;
  23. Tileset * set;
  24. Dynar * panes;
  25. Area * area;
  26. };
  27. #define TEXTURE_TILE "tile"
  28. #define TEXTURE_PLAYER "play"
  29. #define TEXTURE_GEAR "gear"
  30. #define TEXTURE_WEAPON "arms"
  31. #define TEXTURE_FOE "foes"
  32. #define TEXTURE_ITEM "item"
  33. /** Loads an image of the given category and index as a texture. */
  34. Image * image_loadtexture(const char * category, int index) {
  35. char buf[1024];
  36. Image * image;
  37. sprintf(buf, "data/image/%s_%03d.png", category, index);
  38. image = image_load(buf);
  39. return image;
  40. }
  41. /** Cleans up a tilemap. */
  42. Tilemap * tilemap_done(Tilemap * self) {
  43. int index;
  44. if(!self) return NULL;
  45. for(index = 0; index < TILEMAP_PANES; index++) {
  46. tilepane_free(dynar_getptr(self->panes, index));
  47. }
  48. dynar_free(self->panes);
  49. tileset_free(self->set);
  50. /* the area is not owned so we don't free that */
  51. // tilemap_initempty(self);
  52. return self;
  53. }
  54. /** Initializes a tile map */
  55. Tilemap* tilemap_init(Tilemap * self, Tileset * set, int w, int h, Area * unused__) {
  56. int index;
  57. (void) unused__;
  58. if(!self) return NULL;
  59. self->gridw = w;
  60. self->gridh = h;
  61. self->set = set;
  62. if(!self->set) { return NULL; }
  63. self->panes = dynar_new(TILEMAP_PANES, sizeof(Tilepane *));
  64. if(!self->panes) { return NULL; }
  65. for(index = 0; index < TILEMAP_PANES; index++) {
  66. dynar_putptr(self->panes, index, NULL);
  67. }
  68. return self;
  69. }
  70. /** Frees the tile map and initializes it. */
  71. Tilemap * tilemap_free(Tilemap * map) {
  72. tilemap_done(map);
  73. mem_free(map);
  74. return NULL;
  75. }
  76. /** Allocates a new tile map and initializes it. */
  77. Tilemap * tilemap_new(Tileset * set, int w, int h, Area * unused__ ) {
  78. Tilemap * map = STRUCT_ALLOC(Tilemap);
  79. (void) unused__;
  80. if(!tilemap_init(map, set, w, h, NULL)) {
  81. return tilemap_free(map);
  82. }
  83. return map;
  84. }
  85. /** Returns a pointer to the pane at index or NULL if out of range. */
  86. Tilepane * tilemap_pane(Tilemap * self, int index) {
  87. return dynar_getptr(self->panes, index);
  88. }
  89. /** Sets a new tile pane for the pane at indexeth index of the tile map.
  90. * the old pane, if any, will be deleted with tilepane_free
  91. */
  92. Tilepane * tilemap_pane_(Tilemap * self, int index, Tilepane * pane) {
  93. Tilepane * oldpane;
  94. oldpane = tilemap_pane(self, index);
  95. // Replace old pane, so free it.
  96. tilepane_free(oldpane);
  97. dynar_putptr(self->panes, index, pane);
  98. return pane;
  99. }
  100. /** Makes a new tile pane for the pane at indexeth index of the tile map. */
  101. Tilepane * tilemap_panenew(Tilemap * self, int index, int w, int h) {
  102. Tilepane * pane = tilepane_new(self->set, w, h);
  103. return tilemap_pane_(self, index, pane);
  104. }
  105. /** Returns the tile in the tile map in the given layer at the given tile coords. */
  106. Tile * tilemap_get(Tilemap * self, int l, int x, int y) {
  107. Tilepane * pane = tilemap_pane(self, l);
  108. if(!pane) return NULL;
  109. return tilepane_get(pane, x, y);
  110. }
  111. /** Converts the tile's flags to an integer id for the best Thing to
  112. represent this tile. Returns THING_UNUSED if it needs no physical representation. */
  113. int tile_thingkind(Tile * tile) {
  114. if (!tile) return THING_UNUSED;
  115. if (tile_index(tile)<1) return THING_UNUSED;
  116. if (tile_isflag(tile, TILE_WALL)) return THING_WALL;
  117. if (tile_isflag(tile, TILE_STAIR)) return THING_STAIR;
  118. if (tile_isflag(tile, TILE_WATER)) return THING_WATER;
  119. return THING_UNUSED;
  120. }
  121. /** Sets a tile in the tile map to the given tile. */
  122. Tile * tilemap_settile(Tilemap * self, int l, int x, int y, Tile * tile) {
  123. Tile * aidt = NULL;
  124. Tilepane * pane = tilemap_pane(self, l);
  125. if(!pane) return NULL;
  126. aidt = tilepane_set(pane, x, y, tile);
  127. if(!aidt) return NULL;
  128. return tile;
  129. }
  130. /** Sets a tile in the tile map to the tile with the given index. */
  131. Tile * tilemap_setindex(Tilemap * self, int l, int x, int y, int index) {
  132. Tilepane * pane = tilemap_pane(self, l);
  133. Tile * tile = NULL;
  134. if(!pane) return NULL;
  135. tile = tilepane_setindex(pane, x, y, index);
  136. if(!tile) return NULL;
  137. return tile;
  138. }
  139. /** Sets a rectangle area in the tile map to the given tile. */
  140. Tile * tilemap_rect(Tilemap * self, int l,
  141. int x, int y, int w, int h, Tile * tile) {
  142. Tilepane * pane = tilemap_pane(self, l);
  143. if(!pane) return NULL;
  144. return tilepane_rect(pane, x, y, w, h, tile);
  145. }
  146. /** Sets a rectangle area in the tile map to the given tile. */
  147. Tile * tilemap_fill(Tilemap * self, int l, Tile * tile) {
  148. Tilepane * pane = tilemap_pane(self, l);
  149. return tilepane_fill(pane, tile);
  150. }
  151. /** Gets the index of the tile at the given location in the tilemap. */
  152. int tilemap_getindex(Tilemap * self, int l, int x, int y) {
  153. Tilepane * pane = tilemap_pane(self, l);
  154. return (int) tilepane_getindex(pane, x, y);
  155. }
  156. /** Sets the drawing flags of the tile at (x, y) in layer l. */
  157. int tilemap_set_flags(Tilemap * self, int l, int x, int y, int flags) {
  158. Tilepane * pane = tilemap_pane(self, l);
  159. if (!pane) return -1;
  160. return tilepane_set_flags(pane, x, y, flags);
  161. }
  162. /** Gets the drawing flags of the tile at (x, y) in layer l. */
  163. int tilemap_get_flags(Tilemap * self, int l, int x, int y) {
  164. Tilepane * pane = tilemap_pane(self, l);
  165. if (!pane) return -1;
  166. return tilepane_get_flags(pane, x, y);
  167. }
  168. /** Draws a tile map. */
  169. void tilemap_draw(Tilemap * map, Camera * camera) {
  170. int index;
  171. Tilepane * pane;
  172. Tilepane * floor = NULL;
  173. /* XXX the blends and the shadows don't mix well, perhaps draw shadows
  174. * first???
  175. */
  176. for(index = 0; index < TILEMAP_PANES; index++) {
  177. pane = tilemap_pane(map, index);
  178. if (pane) {
  179. tilepane_draw(pane, camera);
  180. if (index == 0) {
  181. tilepane_draw_blends(pane, camera);
  182. floor = pane;
  183. } else if (index > 0) {
  184. tilepane_draw_shadows_of(pane, floor, camera);
  185. }
  186. } else {
  187. LOG_WARNING("Pane missing: %d", index);
  188. }
  189. }
  190. }
  191. /** Draws a layer in the tile map with the given index,
  192. without blends nor shadows. */
  193. void tilemap_draw_layer_tiles(Tilemap * map, Camera * camera, int layer) {
  194. Tilepane * pane;
  195. pane = tilemap_pane(map, layer);
  196. if (pane) {
  197. tilepane_draw(pane, camera);
  198. }
  199. }
  200. /** Draws the blends in a layer in the tile map with the given index,
  201. if it exists. Otherwise does nothing. */
  202. void tilemap_draw_layer_blends(Tilemap * map, Camera * camera, int layer) {
  203. Tilepane * pane;
  204. pane = tilemap_pane(map, layer);
  205. if (pane) {
  206. tilepane_draw_blends(pane, camera);
  207. }
  208. }
  209. /** Draws the shadows a given layer in a tile map casts if it exists
  210. * and isn't equal to 0.
  211. * Otherwise does nothing. */
  212. void tilemap_draw_layer_shadows(Tilemap * map, Camera * camera, int layer) {
  213. Tilepane * pane;
  214. Tilepane * floor;
  215. if (layer < 1) return ;
  216. pane = tilemap_pane(map, layer);
  217. if (!pane) return;
  218. floor = tilemap_pane(map, layer-1);
  219. tilepane_draw_shadows_of(pane, floor, camera);
  220. }
  221. /** Draws a layer in the tile map with the given index,
  222. if it exists. Otherwise does nothing. */
  223. void tilemap_draw_layer(Tilemap * map, Camera * camera, int layer) {
  224. /* Shadows must be drawn before blends otherwise both won't look good. */
  225. tilemap_draw_layer_tiles( map, camera, layer);
  226. tilemap_draw_layer_shadows( map, camera, layer);
  227. tilemap_draw_layer_blends( map, camera, layer);
  228. }
  229. /** Updates the tile map. Currently this animates the tiles. */
  230. void tilemap_update(Tilemap * map, double dt) {
  231. tileset_update(map->set, dt);
  232. }
  233. /** Adds a dynamic thing of the given type to the tile map's area */
  234. Thing * tilemap_addthing(Tilemap * self, int index, int kind, int x, int y, int z,
  235. int w, int h) {
  236. /** XXX this will be hard to find back from the scripting side, fix this! */
  237. return area_new_thing(self->area, kind, x, y, z, w, h);
  238. }
  239. /** Sets up the camera so it will stay locked in to the
  240. given layer of the tile map */
  241. Lockin * tilepane_lockin(Tilepane * pane, Camera * camera) {
  242. float x, y, w, h;
  243. if(!pane) return NULL;
  244. x = 0.0;
  245. y = 0.0;
  246. w = tilepane_wide(pane);
  247. h = tilepane_high(pane);
  248. return camera_newlockin(camera, x, y, w, h);
  249. }
  250. /** Sets up the camera so it will stay locked in to the
  251. extent of the given layer of the tile map. */
  252. Lockin * tilemap_layer_lockin(Tilemap * map,
  253. int layer,
  254. Camera * camera) {
  255. Tilepane * pane;
  256. Lockin * result;
  257. float x, y, w, h;
  258. if (!map) return NULL;
  259. pane = tilemap_pane(map, layer);
  260. return tilepane_lockin(pane, camera);
  261. }
  262. /* Returns the tile map's area. */
  263. Area * tilemap_area(Tilemap * self) {
  264. if(!self) return NULL;
  265. return self->area;
  266. }
  267. /* Returns a thing from this tile map's area. */
  268. Thing * tilemap_thing(Tilemap * self, int index) {
  269. Area * area = tilemap_area(self);
  270. return area_thing(area, index);
  271. }
  272. /* Gets the map's grid size from the largest tile layer */
  273. int tilemap_gridwide(Tilemap * self) {
  274. int wide = 0;
  275. int index;
  276. for (index = 0; index < TILEMAP_PANES; index++) {
  277. int aid = tilepane_gridwide(tilemap_pane(self, index));
  278. if (aid > wide) {
  279. wide = aid;
  280. }
  281. }
  282. return wide;
  283. }
  284. /* Gets the map's grid size from the largest tile layer */
  285. int tilemap_gridhigh(Tilemap * self) {
  286. int high = 0;
  287. int index;
  288. for (index = 0; index < TILEMAP_PANES; index++) {
  289. int aid = tilepane_gridhigh(tilemap_pane(self, index));
  290. if (aid > high) {
  291. high = aid;
  292. }
  293. }
  294. return high;
  295. }
  296. /** Returns the almount of tile panes in this map. */
  297. int tilemap_panes(Tilemap * self) {
  298. (void) self;
  299. return TILEMAP_PANES;
  300. }
  301. /** Sets up automatic blending for this tile map. This is called automatically
  302. after loading the Tilemap */
  303. bool tilemap_init_blend(Tilemap * self) {
  304. bool res = true;
  305. bool aid;
  306. int index;
  307. for (index = 0; index < TILEMAP_PANES; index++) {
  308. aid = tilepane_init_blend(tilemap_pane(self, index), index);
  309. res = aid && res;
  310. }
  311. return res;
  312. }
  313. /* Returns the tileset used for this tile map. */
  314. Tileset * tilemap_tileset(Tilemap * me) {
  315. if (!me) return NULL;
  316. return me->set;
  317. }
  318. /** Returns the firstgid for the tileset of this map,
  319. * or negative on error */
  320. /* Returns the tileset used for this tile map. */
  321. int tilemap_firstgid(Tilemap * me) {
  322. Tileset * set = tilemap_tileset(me);
  323. if (!set) return -1;
  324. return tileset_firstgid(set);
  325. }
  326. #ifdef SEPARATE_TILEMAP_LOADER
  327. /* Amount of tilemaps that can be loaded at oce. */
  328. #ifndef ERUTA_TILEMAPS_MAX
  329. #define ERUTA_TILEMAPS_MAX 16
  330. #endif
  331. /* "Globally" loaded tile maps. Allow up to ERUTA_TILEMAPS_MAX tile maps to be
  332. * loaded at the same time. */
  333. static Tilemap * tilemaps[ERUTA_TILEMAPS_MAX];
  334. static int active_tilemap = -1;
  335. /* Currently active tile map, if any. Negative means, none active. */
  336. int tilemaps_max(void) {
  337. return ERUTA_TILEMAPS_MAX;
  338. }
  339. int tilemaps_out_of_bounds(int index) {
  340. if (index < 0) return TRUE;
  341. if (index >tilemaps_max()) return TRUE;
  342. return false;
  343. }
  344. Tilemap * tilemaps_put_raw(int index, Tilemap * map) {
  345. if(tilemaps_out_of_bounds(index)) return NULL;
  346. return tilemaps[index] = map;
  347. }
  348. /* Puts map at index, unloading any previously loaded map. */
  349. Tilemap * tilemaps_put(int index, Tilemap * map) {
  350. if(tilemaps_out_of_bounds(index)) return NULL;
  351. if(tilemaps[index]) tilemap_free(tilemaps[index]);
  352. return tilemaps[index] = map;
  353. }
  354. int tilemaps_init(void) {
  355. int index;
  356. for(index = 0; index < tilemaps_max(); index ++) {
  357. tilemaps_put_raw(index, NULL);
  358. }
  359. }
  360. Tilemap * tilemaps_get(int index) {
  361. if(tilemaps_out_of_bounds(index)) return NULL;
  362. return tilemaps[index];
  363. }
  364. /* Deallocates all loaded tile maps. */
  365. int tilemaps_done(void) {
  366. int index;
  367. for(index = 0; index < tilemaps_max(); index ++) {
  368. tilemaps_put(index, NULL);
  369. }
  370. }
  371. #endif