area.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526
  1. #include "eruta.h"
  2. #include "area.h"
  3. #include "tilemap.h"
  4. #include "bump.h"
  5. #include "thing.h"
  6. #include "mem.h"
  7. #include "flags.h"
  8. #include "draw.h"
  9. #include "sprite.h"
  10. #include "callrb.h"
  11. #include "monolog.h"
  12. #include "thing_struct.h"
  13. /** Scale factor. */
  14. #define AREA_SCALE_BY (32.0lf)
  15. /** Scales int by scale factor */
  16. #define AREA_SCALE_INT(I) ((double)((INT) I)>>5))
  17. /*
  18. An area is an in game region that corresponds with a single loaded tile map
  19. and that keeps track of the physics and location of all in-game objects.
  20. An area consists of a chipmunk cpSpace that simulates the dynamics,
  21. and a list of Things, that is, in game objects. It also contains a reference
  22. to a SpriteList (that is owned by state).
  23. Division of the data locations: visual and physics engine: in C.
  24. Logic/game/character data: in scripting engine.
  25. */
  26. /* Start with space for 20000 things. */
  27. #define AREA_THINGS 20000
  28. struct Area_ {
  29. BumpWorld * world;
  30. int lastid;
  31. Thing * things[AREA_THINGS];
  32. Thing * things_todraw[AREA_THINGS];
  33. BumpTilemap * bumpmap;
  34. int draw_physics;
  35. };
  36. /** Gets the amount of possible things for this area */
  37. int area_maxthings(Area * area) {
  38. (void) area;
  39. return AREA_THINGS;
  40. }
  41. /** Gets the thing for the given thing ID. */
  42. Thing * area_thing(Area * area, int index) {
  43. if (index < 0) return NULL;
  44. if (index > AREA_THINGS) return NULL;
  45. if (!area) return NULL;
  46. return area->things[index];
  47. }
  48. /** Sets the thing for the given thing ID. */
  49. Thing * area_thing_(Area * area, int index, Thing * set) {
  50. if (index < 0) return NULL;
  51. if (index > AREA_THINGS) return NULL;
  52. if (!area) return NULL;
  53. return area->things[index] = set;
  54. }
  55. /** Returns the first unused Thing ID. Internally walks over
  56. * the known things and finds an empty cell. Returns negative on error. */
  57. int area_get_unused_thing_id(Area * self) {
  58. int index, stop;
  59. if (!self) return -1;
  60. stop = area_maxthings(self);
  61. for (index = 0; index < stop; index++) {
  62. Thing * thing = area_thing(self, index);
  63. if(!thing) {
  64. return index;
  65. }
  66. }
  67. return -3;
  68. }
  69. /** Puts a thing inside the area. Returns NULL on error.
  70. returns the thing set if ok. Sets the thing's id to it's
  71. position in the internal array for things the area has. */
  72. Thing * area_add_thing(Area * area, int index, Thing * thing) {
  73. if (!thing) return NULL;
  74. if (index < 0 ) return NULL;
  75. if (index > AREA_THINGS) return NULL;
  76. if(!area_thing_(area, index, thing)) return NULL;
  77. thing_id_(thing, index);
  78. /* Set last used id to index if needed */
  79. if (area->lastid < index) { area->lastid = index; }
  80. /* Don't forget to add physical body and hull to the space if needed. */
  81. bumpworld_add_body(area->world, thing->physical);
  82. bumpworld_add_hull(area->world, thing->hull);
  83. /* Fix up drawing array. */
  84. area_update_things(area);
  85. return thing;
  86. }
  87. /** Set the tile map to use for this area. */
  88. Tilemap *
  89. area_addmap(Area * area, Tilemap * map) {
  90. return bumpworld_tilemap_(area->world, map);
  91. }
  92. /** Returns the static body that this area uses for static things.
  93. * Removed, since not needed because bump uses real tile maps and not static bodies.
  94. */
  95. /* Removes the thing from the area, but does not deallocate it.
  96. * Returns thing if sucessful. */
  97. Thing * area_remove_thing(Area * area, Thing * thing) {
  98. if (!thing) return NULL;
  99. if (thing->id<0) return NULL;
  100. if (thing->kind == THING_UNUSED) return NULL;
  101. bumpworld_remove_hull(area->world, thing->hull);
  102. bumpworld_remove_body_only(area->world, thing->physical);
  103. bumpworld_delete_hulls_for(area->world, thing->physical);
  104. area_thing_(area, thing->id, NULL);
  105. /* Fix up drawing array. */
  106. area_update_things(area);
  107. return thing;
  108. }
  109. /* Removes a thing from the area, selected by ID and deallocates it. */
  110. int area_delete_thing(Area * area, int index) {
  111. Thing * thing = area_thing(area, index);
  112. Thing * del = area_remove_thing(area, thing);
  113. if(thing && del) {
  114. thing_free(thing);
  115. }
  116. return 0;
  117. }
  118. /* Cleans up the things of the area */
  119. Area * area_cleanupthings(Area * self) {
  120. int index, stop;
  121. if(!self) return NULL;
  122. stop = area_maxthings(self);
  123. for (index= 0; index < stop; index++) {
  124. area_delete_thing(self, index);
  125. }
  126. return self;
  127. }
  128. /* Empties the things of an area. Does not destroy them! */
  129. Area * area_emptythings(Area * self) {
  130. int index, stop;
  131. if (!self) return NULL;
  132. stop = area_maxthings(self);
  133. for (index= 0; index < stop; index++) {
  134. area_thing_(self, index, NULL);
  135. }
  136. return self;
  137. }
  138. /** Deinitializes an area and returns self. */
  139. Area * area_done(Area * self) {
  140. if(!self) return self;
  141. if(!self->world) return self;
  142. area_cleanupthings(self);
  143. bumpworld_free(self->world);
  144. self->world = NULL;
  145. self->draw_physics = FALSE;
  146. return self;
  147. }
  148. /** Frees an area. Returns NULL. */
  149. Area * area_free(Area * self) {
  150. if(area_done(self)) {
  151. mem_free(self);
  152. }
  153. return NULL;
  154. }
  155. /** Allocates an area. */
  156. Area * area_alloc() {
  157. return STRUCT_ALLOC(Area);
  158. }
  159. /** Initializes an area. */
  160. Area * area_init(Area * self) {
  161. if(!self) return NULL;
  162. self->lastid = 0;
  163. self->world = bumpworld_new();
  164. if (!self->world) goto out_of_memory;
  165. area_emptythings(self);
  166. self->bumpmap = NULL;
  167. self->draw_physics = FALSE;
  168. // area_setup_default_collision_handlers(self, self);
  169. return self;
  170. out_of_memory:
  171. area_done(self);
  172. return NULL;
  173. }
  174. /** Updates the things in the area, must be called whan adding or deleting a thing too. */
  175. void area_update_things(Area * self) {
  176. int index;
  177. int subindex = 0;
  178. /* Empty the draw queue to avoid stale references after deleting a thing
  179. * or it's physical body. */
  180. for(index = 0; index < AREA_THINGS; index++) {
  181. self->things_todraw[index] = NULL;
  182. }
  183. for(index = 0; index < AREA_THINGS; index++) {
  184. Thing * thing = area_thing(self, index);
  185. if (thing && thing->physical) {
  186. self->things_todraw[subindex] = thing;
  187. subindex++;
  188. }
  189. }
  190. /** Sort drawing array so the painter's algorihm can be used. */
  191. qsort(self->things_todraw, subindex, sizeof(Thing*), thing_compare_for_drawing);
  192. }
  193. /** Sets the area so it will draw its physics
  194. * bounds boxes when it is drawn or not.
  195. */
  196. void area_draw_physics_(Area * self, int draw) {
  197. self->draw_physics = draw;
  198. }
  199. /** Checks if the area draws its physics or not. */
  200. int area_draw_physics(Area * self) {
  201. return self->draw_physics;
  202. }
  203. /** Makes a new area. */
  204. Area * area_new() {
  205. return area_init(area_alloc());
  206. }
  207. /** Returns the BumpWorld that the area uses for dynamics modelling. */
  208. BumpWorld * area_world(Area * self) {
  209. if (!self) return NULL;
  210. return self->world;
  211. }
  212. /** Makes a new thing and adds it to the area. Return it or NULL on error. */
  213. Thing * area_new_thing(Area * self, int kind,
  214. int x, int y, int z, int w, int h) {
  215. Thing * thing;
  216. int index;
  217. index = area_get_unused_thing_id(self);
  218. thing = thing_new_dynamic(self, index, kind, x, y, z, w, h);
  219. if (!area_add_thing(self, index, thing)) {
  220. return thing_free(thing);
  221. }
  222. return thing;
  223. }
  224. /** Makes a new thing and returns it's ID. */
  225. int area_new_thing_id(Area * self, int kind, int x, int y, int z, int w, int h) {
  226. Thing * thing;
  227. thing = area_new_thing(self, kind, x, y, z, w, h);
  228. return thing_id(thing);
  229. }
  230. /** Sets the current tile map of the area. */
  231. ERES area_tilemap_(Area * self, Tilemap * map) {
  232. int wide, high;
  233. if (map) {
  234. wide = tilemap_gridwide(map);
  235. high = tilemap_gridhigh(map);
  236. } else {
  237. /* No map so this is whatever, I think. */
  238. wide = 640;
  239. high = 480;
  240. }
  241. bumpworld_tilemap_(self->world, map);
  242. return ERES_OK;
  243. }
  244. /** Draws all things in an area taking the camera into account. */
  245. void area_draw(Area * self, Camera * camera) {
  246. int index;
  247. for(index = 0; index < (self->lastid + 1); index++) {
  248. Thing * thing = self->things_todraw[index];
  249. /* If we encounter a NULL, we're all done drawing. */
  250. if(!thing) break;
  251. thing_draw(thing, camera);
  252. }
  253. #ifdef ERUTA_DEBUG_DRAW
  254. bumpworld_draw_debug(self->world);
  255. #endif
  256. }
  257. /** Draws all things in an area taking the camera and layer into account. */
  258. void area_draw_layer (Area * self, Camera * camera, int layer) {
  259. int index;
  260. for (index = 0; index < (self->lastid + 1); index++) {
  261. Thing * thing = self->things_todraw[index];
  262. /* If we encounter a NULL, we're all done drawing. */
  263. if(!thing) break;
  264. /* Only draw current layer. */
  265. if(thing_z(thing) != layer) {
  266. continue;
  267. }
  268. thing_draw(thing, camera);
  269. }
  270. if (self->draw_physics) {
  271. bumpworld_draw_debug(self->world);
  272. }
  273. }
  274. /** Updates the area */
  275. void area_update(Area * self, double dt) {
  276. int subindex = 0;
  277. int index;
  278. bumpworld_update(self->world, dt);
  279. area_update_things(self);
  280. for(index = 0; index < (self->lastid + 1); index++) {
  281. Thing * thing = area_thing(self, index);
  282. /* this is a bandaid, somehow uninitialized things are stored in the area. */
  283. if (thing && thing->physical) {
  284. thing_update(thing, dt);
  285. } else if (thing && (thing->id > AREA_THINGS)) {
  286. LOG_WARNING("Corrupted thing detected! %p", thing);
  287. }
  288. }
  289. }
  290. /* Helper for callback wrapper. */
  291. struct area_find_hulls_helper {
  292. int (* callback)(Thing * thing, void * extra);
  293. void * extra;
  294. };
  295. /* Callback wrapper. */
  296. static int area_find_hulls_callback(BumpHull * hull, void * extra) {
  297. struct area_find_hulls_helper * helper = extra;
  298. Thing * thing = bumphull_thing(hull);
  299. if (thing) {
  300. return helper->callback(thing, helper->extra);
  301. }
  302. return 0;
  303. }
  304. /** Finds all things in a given rectangle and calls the callback for each of them.
  305. * Returns 0. If the callback returns nonzero returns this in stead immediately. */
  306. int area_find_things(Area * self, int x, int y, int w, int h, void * extra,
  307. int callback(Thing * thing, void * extra)) {
  308. struct area_find_hulls_helper helper;
  309. BumpAABB bounds = bumpaabb_make_int(x, y, w, h);
  310. helper.callback = callback;
  311. helper.extra = extra;
  312. return bumpworld_find_hulls(self->world, bounds, &helper, area_find_hulls_callback);
  313. }
  314. /* Avoid allocation in the function below. */
  315. static BumpHull * area_hulls[AREA_THINGS];
  316. /** Finds all things in a given rectangle and returns
  317. * up to max_things of them in the array things.
  318. * Returns the amount of things found or negative on error. */
  319. int area_find_and_fetch_things(Area * self, int x, int w, int y, int h,
  320. Thing ** things, int max_things) {
  321. int index, result;
  322. BumpAABB bounds = bumpaabb_make_int(x, y, w, h);
  323. int amount = bumpworld_find_and_fetch_hulls(self->world, bounds, area_hulls, AREA_THINGS);
  324. int stop = amount;
  325. if (stop < max_things) stop = max_things;
  326. result = 0;
  327. for (index = 0; index < stop; index ++) {
  328. Thing * thing = bumphull_thing(area_hulls[index]);
  329. if (thing) {
  330. things[result] = thing;
  331. result++;
  332. }
  333. }
  334. return result;
  335. }
  336. /** Gets the thing at index index and adds a new hull to it */
  337. BumpHull * area_add_hull(Area * self, int index, int kind,
  338. int x, int y, int z, int w, int h) {
  339. BumpHull * hull;
  340. Thing * thing;
  341. BumpAABB aabb = bumpaabb_make_int(x, y, w, h);
  342. thing = area_thing(self, index);
  343. return bumpworld_new_hull(self->world, thing->physical, bevec(x,y), aabb, z, kind);
  344. }
  345. /* Removes a hull from the area and also from the body it was attached
  346. * to. */
  347. Area * area_delete_hull(Area * self, int index) {
  348. if (bumpworld_delete_hull_index(self->world, index)) return self;
  349. return NULL;
  350. }
  351. /* Removes a body from the area and also all hulls attached to it from the area. */
  352. Area * area_delete_body(Area * self, int index) {
  353. if(bumpworld_delete_body_index(self->world, index)) return self;
  354. return NULL;
  355. }
  356. /** Sets a flag on the main hull of the Thing indicated by index. */
  357. int area_set_thing_hull_flag(Area * me, int index, int flag) {
  358. Thing * thing;
  359. if (!me) return 0;
  360. thing = area_thing(me, index);
  361. return thing_set_hull_flag(thing, flag);
  362. }
  363. /** Unsets a flag for the main hull of the thing. */
  364. int area_unset_thing_hull_flag(Area * me, int index, int flag) {
  365. Thing * thing;
  366. if (!me) return 0;
  367. thing = area_thing(me, index);
  368. return thing_unset_hull_flag(thing, flag);
  369. }
  370. /** Sets all flags for the main hull of the thing. */
  371. int area_thing_hull_flags_(Area * me, int index, int flags) {
  372. Thing * thing;
  373. if (!me) return 0;
  374. thing = area_thing(me, index);
  375. return thing_hull_flags_(thing, flags);
  376. }
  377. /** Gets all flags for the main hull of the thing. */
  378. int area_thing_hull_flags(Area * me, int index) {
  379. Thing * thing;
  380. if (!me) return 0;
  381. thing = area_thing(me, index);
  382. return thing_hull_flags(thing);
  383. }
  384. /** Sets a flag on the hull indicated by index. */
  385. int area_set_hull_flag(Area * me, int index, int flag) {
  386. if (!me) return 0;
  387. return bumpworld_set_hull_flag(me->world, index, flag);
  388. }
  389. /** Unsets a flag for the hull indicated by index. */
  390. int area_unset_hull_flag(Area * me, int index, int flag) {
  391. if (!me) return 0;
  392. return bumpworld_unset_hull_flag(me->world, index, flag);
  393. }
  394. /** Sets all flags for the hull indicated by index. */
  395. int area_hull_flags_(Area * me, int index, int flags) {
  396. if (!me) return 0;
  397. return bumpworld_hull_flags_(me->world, index, flags);
  398. }
  399. /** Gets all flags for the hull indicated by index. */
  400. int area_hull_flags(Area * me, int index) {
  401. if (!me) return 0;
  402. return bumpworld_hull_flags(me->world, index);
  403. }
  404. int area_thing_hull_group(Area * me , int index) {
  405. if (!me) return -1;
  406. return thing_hull_group(area_thing(me, index));
  407. }
  408. int area_thing_hull_group_(Area * me, int index, int group) {
  409. if (!me) return -1;
  410. return thing_hull_group_(area_thing(me, index), group);
  411. }
  412. /** Returns the thing related to the hull's body, if any.
  413. * This is in area.c for dependency reasons.
  414. */
  415. Thing * bumphull_thing(BumpHull * hull) {
  416. return bumphull_body_data(hull);
  417. }
  418. #define THING_TRACK_DELTA 32.0 * 4
  419. #ifdef COMMENT_
  420. /** A tracker function for tracking a Thing. Only works with dynamic things. */
  421. int thing_track(Tracker * tracker, void * data) {
  422. Thing * thing = NULL;
  423. if(!tracker || !tracker->camera) return TRACKER_ERROR;
  424. thing = (Thing *) tracker->target;
  425. if(thing_static_p(thing)) return TRACKER_ERROR;
  426. // TODO: correct with half width and half height
  427. camera_centerdelta_(tracker->camera, thing_p(thing), THING_TRACK_DELTA);
  428. return TRACKER_DONE;
  429. }
  430. #endif