state.c 29 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033
  1. #include "eruta.h"
  2. #include "mem.h"
  3. #include "state.h"
  4. #include "camera.h"
  5. #include "sound.h"
  6. #include "tilemap.h"
  7. #include "tileio.h"
  8. #include "dynar.h"
  9. #include "draw.h"
  10. #include "mode.h"
  11. #include "fifi.h"
  12. #include "rh.h"
  13. #include "toruby.h"
  14. #include "event.h"
  15. #include "widget.h"
  16. #include "area.h"
  17. #include "thing.h"
  18. #include "sprite.h"
  19. #include "scegra.h"
  20. #include "monolog.h"
  21. #include "callrb.h"
  22. #include "store.h"
  23. #include "zori.h"
  24. /* The data struct contains all global state and other data of the application.
  25. */
  26. struct State_ {
  27. /* State flags. */
  28. BOOL busy;
  29. BOOL fullscreen;
  30. BOOL audio;
  31. /* Graphics mode. XXX: I think???? :P */
  32. int32_t modeno;
  33. /*
  34. There are two fonts for now, ttf and font. Font is a plain font
  35. for emergency use, ttf is the normal font for the console.
  36. */
  37. ALLEGRO_FONT * font;
  38. ALLEGRO_FONT * ttf;
  39. /* Some default colors */
  40. ALLEGRO_COLOR colors[STATE_COLORS];
  41. /* Display */
  42. ALLEGRO_DISPLAY * display;
  43. ALLEGRO_EVENT_QUEUE * queue;
  44. char * errmsg;
  45. /* FPS handling. */
  46. double fpsnow, fpstime, fps;
  47. int frames;
  48. /* Background image that can be set behind the tile map. */
  49. ALLEGRO_BITMAP * background_image;
  50. /* Background color, in case of no tile map */
  51. ALLEGRO_COLOR background_color;
  52. /* Active tile map, linked from and loaded through a Store ID. */
  53. Tilemap * active_map;
  54. int active_map_id;
  55. /* Does the area needs to be displayed or not. */
  56. int show_area;
  57. /* Does the graph needs to be displayed or not */
  58. int show_graph;
  59. /* Does the FPS counter needs to be displayed or not? */
  60. int show_fps;
  61. /* Logical and physical game objects. This one is always active, regardless of the tile map. */
  62. Area * area;
  63. // View camera for the area, tile map and particle engine.
  64. Camera * camera;
  65. /* Mode is removed, this will be handled on the scripting side. */
  66. /* Sprite subsystem */
  67. SpriteList * sprites;
  68. /* Ruby subsystem */
  69. Ruby * ruby;
  70. /*
  71. The ruby and error message GUI console.
  72. Implemented in C so it's usable even if there are script bugs.
  73. */
  74. struct zori_console * console;
  75. /* The current actor, controlled by the player. */
  76. Thing * actor;
  77. };
  78. /** State variable. */
  79. static State * global_state_ = NULL;
  80. /** Various loggers. One for stdout if not on windows,
  81. * one to a file and one to the Console */
  82. int state_console_logf(char * file, int line, char * level,
  83. void * data, char * format, va_list args) {
  84. struct zori_console * console = data;
  85. if (console) {
  86. zori_console_printf(console, "%s %s %d:", level, file, line);
  87. return zori_console_vprintf(console, format, args);
  88. }
  89. return -1;
  90. }
  91. DEFINE_STDERR_LOGGER(state_stderr_logger);
  92. DEFINE_FILE_LOGGER(state_file_logger);
  93. DEFINE_LOGGER(state_console_logger, state_console_logf, NULL);
  94. /** Gets the global state data, or NULL if not set. */
  95. State * state_get() {
  96. return global_state_;
  97. }
  98. /** Sets the given state data as the global state data for this apllication.
  99. * returns the *previous* state data pointer or NULL if it was not set yet.
  100. */
  101. State * state_set(State * state) {
  102. State * oldstate = global_state_;
  103. global_state_ = state;
  104. return oldstate;
  105. }
  106. /** Returns the state's active tile map. */
  107. Tilemap * state_active_map(State * state) {
  108. if(!state) return NULL;
  109. return state->active_map;
  110. }
  111. /** Sets the state's active tile map. Also sets it in the state's area, and
  112. disables all previous camera panners and lockins, and sets up a basic lockin on
  113. map layer 0 if the map is not NULL. */
  114. Tilemap * state_active_map_(State * state, Tilemap * map) {
  115. if(!state) return NULL;
  116. if (state->area) {
  117. area_tilemap_(state->area, map);
  118. }
  119. if (state->camera) {
  120. camera_freepanners(state->camera);
  121. camera_freelockins(state->camera);
  122. }
  123. state->active_map = map;
  124. if(state->active_map) {
  125. tilemap_layer_lockin(state->active_map, 0, state->camera);
  126. }
  127. return state->active_map;
  128. }
  129. /** Gets the store index of the state's active tile map, or -1 if none set. */
  130. int state_active_map_id(State * state) {
  131. if(!state) return -1;
  132. return state->active_map_id;
  133. }
  134. /** Sets the state's active tile from the Store system index.
  135. * Returns negative on failure, or the index set. Disables the active tile map if index is < 0 */
  136. int state_active_map_id_(State * state, int index) {
  137. Tilemap * map;
  138. if (!state) return -1;
  139. if (index < 0) {
  140. state->active_map_id = -1;
  141. state_active_map_(state, NULL);
  142. return -1;
  143. }
  144. map = store_get_other(index, RESOR_TILEMAP);
  145. if (!map) {
  146. // refuse to load nonexisting map
  147. return -2;
  148. }
  149. state_active_map_(state, map);
  150. return -1;
  151. }
  152. /** Returns the state's area. */
  153. Area * state_area(State * state) {
  154. if (!state) return NULL;
  155. return state->area;
  156. }
  157. /** Return's the state's sprite list */
  158. SpriteList * state_sprites(State * state) {
  159. if (!state) return NULL;
  160. return state->sprites;
  161. }
  162. /** Allocates a state struct */
  163. State * state_alloc() {
  164. return STRUCT_ALLOC(State);
  165. }
  166. /** Frees a state struct. */
  167. void state_free(State * self) {
  168. /* Shut down audio */
  169. audio_done();
  170. spritelist_free(self->sprites);
  171. self->sprites = NULL;
  172. area_free(self->area);
  173. self->area = NULL;
  174. /* Disable the active tile map */
  175. state_active_map_id_(self, -1);
  176. /* Disable gui. */
  177. zori_shutdown();
  178. rh_free(self->ruby);
  179. self->console = NULL; /* disable console immediately. */
  180. /* Deallocate stored objects. */
  181. store_done();
  182. // font_free(self->font);
  183. al_destroy_display(self->display);
  184. camera_free(self->camera);
  185. al_uninstall_system();
  186. /* End logging. */
  187. monolog_done();
  188. STRUCT_FREE(self);
  189. }
  190. /** Sets error message for state and returns NULL. */
  191. State * state_errmsg_(State * state, char * mesg) {
  192. state->errmsg = mesg;
  193. return NULL;
  194. }
  195. /** Gets error message for state. */
  196. char * state_errmsg(State * state) {
  197. return state->errmsg;
  198. }
  199. /** Registers an event source for this state */
  200. State * state_eventsource(State * state, ALLEGRO_EVENT_SOURCE * src) {
  201. al_register_event_source(state->queue, src);
  202. return state;
  203. }
  204. /** Gets a color from the state' color list. NOT bound checked! */
  205. ALLEGRO_COLOR state_color(State * state, int color) {
  206. return state->colors[color];
  207. }
  208. /** Sets a color to the state' color list. NOT bound checked! */
  209. ALLEGRO_COLOR state_color_f(State * state, int color,
  210. float r, float g, float b, float a) {
  211. return state->colors[color] = al_map_rgba_f(r, g, b, a);
  212. }
  213. /** Gets Ruby interpreter for state. */
  214. Ruby * state_ruby(State * state) {
  215. return state->ruby;
  216. }
  217. /** Gets console intepreter for state. */
  218. struct zori_console * state_console(State * state) {
  219. return state->console;
  220. }
  221. /* Creates a new sprite in the sprite list. */
  222. Sprite * state_new_sprite(State * state) {
  223. SpriteList * list = state_sprites(state);
  224. return spritelist_new_sprite(list);
  225. }
  226. /* Creates a new sprite in the sprite list and returns it's id. */
  227. int state_new_sprite_id(State * state) {
  228. SpriteList * list = state_sprites(state);
  229. return spritelist_new_sprite_id(list);
  230. }
  231. /* Returns a sprite from the state's sprite list. */
  232. Sprite * state_sprite(State * state, int index) {
  233. SpriteList * list = state_sprites(state);
  234. return spritelist_sprite(list, index);
  235. }
  236. /* Loads a layer of a sprite from a vpath. Sprite layer is in
  237. ulpcss format. */
  238. int state_sprite_load_builtin
  239. (State * state, int sprite_index, int layer_index, char * vpath, int layout) {
  240. return spritelist_load_sprite_layer_with_builtin_layout(
  241. state_sprites(state), sprite_index, layer_index, vpath, layout
  242. );
  243. }
  244. /* Gets a thing from the state's area. */
  245. Thing * state_thing(State * state, int index) {
  246. Area * area = state_area(state);
  247. return area_thing(area, index);
  248. }
  249. /* Makes a new dynamic thing in the state's active area. */
  250. Thing * state_newthing(State * state, int kind,
  251. int x, int y, int z, int w, int h) {
  252. Area * area = state_area(state);
  253. return area_new_thing(area, kind, x, y, z, w, h);
  254. }
  255. /* Makes a new dynamic thing and returns it's index, or
  256. negative if it could not be created. */
  257. int state_newthingindex(State * state, int kind,
  258. int x, int y, int z, int w, int h) {
  259. Area * area = state_area(state);
  260. return area_new_thing_id(area, kind, x, y, z, w, h);
  261. }
  262. /* Looks op both the Thing and the Sprite by index and
  263. * links the Thing to the Sprite. Returns the sprite index set or negative on error.
  264. * Both sprite and thing must already exist for this to work.
  265. */
  266. int state_thing_sprite_(State * state, int thing_index, int sprite_index) {
  267. Thing * thing; Sprite * sprite;
  268. thing = state_thing(state, thing_index);
  269. if (!thing) { return -1; }
  270. sprite = state_sprite(state, sprite_index);
  271. if (!sprite) { return -2; }
  272. thing_sprite_(thing, sprite);
  273. return sprite_index;
  274. }
  275. /* Looks up the thing by index and set it's pose. Returns negative on error,
  276. or if sucessful, the pose set. */
  277. int state_thing_pose_(State * state, int thing_index, int pose) {
  278. Thing * thing;
  279. thing = state_thing(state, thing_index);
  280. if(!thing) return -1;
  281. thing_pose_(thing, pose);
  282. return pose;
  283. }
  284. /* Looks up the thing by index and set it's direction. Returns negative on error,
  285. or if sucessful, the direction set. */
  286. int state_thing_direction_(State * state, int thing_index, int direction) {
  287. Thing * thing;
  288. thing = state_thing(state, thing_index);
  289. if(!thing) return -1;
  290. thing_direction_(thing, direction);
  291. return direction;
  292. }
  293. /* Looks up the thing by index and let the state's camera track it.
  294. * If index is negative, stop tracking in stead.
  295. */
  296. int state_camera_track_(State * state, int thing_index) {
  297. Thing * thing;
  298. if (thing_index < 0) {
  299. camera_track_(state_camera(state), NULL);
  300. return -2;
  301. }
  302. thing = state_thing(state, thing_index);
  303. if(!thing) return -1;
  304. camera_track_(state_camera(state), thing);
  305. thing_direction_(thing, thing_index);
  306. return thing_index;
  307. }
  308. /* Sets up the state's camera to track the numbered thing. */
  309. int state_cameratrackthing(State * state, int thing_index) {
  310. Thing * thing = state_thing(state, thing_index);
  311. if (thing) {
  312. camera_track_(state_camera(state), thing);
  313. return 0;
  314. }
  315. return -1;
  316. }
  317. /* Lock in the state's camera to the current active tile map's given layer.
  318. * Returns negative if no tile map is currently active.
  319. */
  320. int state_lockin_maplayer(State * state, int layer) {
  321. if(!state_active_map(state)) {
  322. return -1;
  323. } else {
  324. tilemap_layer_lockin(state_active_map(state), layer, state_camera(state));
  325. }
  326. return 0;
  327. }
  328. /* Loads a named tile map from the map folder. */
  329. /* This function is obsolete. Load tile maps though script / store now.
  330. int state_loadtilemap_vpath(State * self, char * vpath) {
  331. TilemapLoadExtra extra;
  332. extra.area = self->area;
  333. self->loadingmap = fifi_load_vpath(tilemap_fifi_load, &extra, vpath);
  334. if(!self->loadingmap) return -1;
  335. tilemap_free(self->nowmap);
  336. self->nowmap = self->loadingmap;
  337. return 0;
  338. }
  339. */
  340. /* Sets the state current active actor to the thing with the given index.
  341. * Does not change if no such thing is found;
  342. */
  343. /* Obsolete. The scripts manage the active actor now.
  344. int state_actorindex_(State * self, int thing_index) {
  345. Thing * thing;
  346. thing = state_thing(self, thing_index);
  347. if(!thing) return -1;
  348. self->actor = thing;
  349. return thing_index;
  350. }
  351. */
  352. /* Returns the current active actor of the state. */
  353. /* Obsolete. The scripts manage the active actor now.
  354. Thing * state_actor(State * self) {
  355. if(!self) return NULL;
  356. return self->actor;
  357. }
  358. */
  359. #define STATE_MODES 10
  360. int state_initjoystick(State * self) {
  361. int num, index, snum, sindex, bnum, bindex, anum, aindex;
  362. (void) self;
  363. if(!al_install_joystick()) return FALSE;
  364. num = al_get_num_joysticks();
  365. LOG_NOTE("Found %d joysticks:\n", num);
  366. for(index = 0; index < num; index ++) {
  367. ALLEGRO_JOYSTICK * joy = al_get_joystick(index);
  368. if(!al_get_joystick_active(joy)) continue;
  369. LOG_NOTE("Joystick nr %d, name: %s,", index, al_get_joystick_name(joy));
  370. snum = al_get_joystick_num_sticks(joy);
  371. LOG_NOTE("\n%d sticks: ", snum);
  372. for(sindex = 0; sindex < snum; sindex++) {
  373. LOG_NOTE("%s, ", al_get_joystick_stick_name(joy, sindex));
  374. anum = al_get_joystick_num_axes(joy, sindex);
  375. LOG_NOTE("%d axes: ", anum);
  376. for (aindex = 0; aindex < anum; aindex++) {
  377. LOG_NOTE("%s, ",
  378. al_get_joystick_axis_name(joy, sindex, aindex));
  379. }
  380. }
  381. bnum = al_get_joystick_num_buttons(joy);
  382. LOG_NOTE("\n%d buttons: ", bnum);
  383. for(bindex = 0; bindex < bnum; bindex++) {
  384. LOG_NOTE("%s, ", al_get_joystick_button_name(joy, bindex));
  385. }
  386. LOG_NOTE(".\n");
  387. }
  388. LOG_NOTE("\n");
  389. return num;
  390. }
  391. /** Initializes the state. It opens the screen, keyboards,
  392. interpreter, etc. Get any error with state_errmsg if
  393. this returns NULL. */
  394. State * state_init(State * self, BOOL fullscreen) {
  395. if(!self) return NULL;
  396. int flags = 0;
  397. // initialize logging first
  398. if (!monolog_init()) {
  399. return state_errmsg_(self, "Could not init logging.");
  400. }
  401. // Initialize loggers
  402. monolog_add_logger(NULL, &state_stderr_logger);
  403. monolog_add_logger(fopen("eruta.log", "a"), &state_file_logger);
  404. // initialize log levels
  405. LOG_ENABLE_ERROR();
  406. LOG_ENABLE_WARNING();
  407. LOG_ENABLE_NOTE();
  408. LOG_NOTE("Starting logging", "");
  409. self->busy = TRUE;
  410. self->fullscreen = fullscreen;
  411. self->audio = FALSE;
  412. state_errmsg_(self, "OK!");
  413. // Initialize Ruby scripting
  414. self->ruby = rh_new();
  415. if(!self->ruby) {
  416. return state_errmsg_(self, "Could not init Ruby.\n");
  417. }
  418. tr_init(self->ruby);
  419. // Initialize Allegro 5 and addons
  420. if (!al_init()) {
  421. return state_errmsg_(self, "Could not init Allegro.\n");
  422. }
  423. al_init_image_addon();
  424. al_init_font_addon();
  425. al_init_primitives_addon();
  426. if(!al_init_ttf_addon()) {
  427. return state_errmsg_(self, "Could not init TTF extension.\n");
  428. }
  429. // Install the keyboard handler
  430. if (!al_install_keyboard()) {
  431. return state_errmsg_(self, "Error installing keyboard.\n");
  432. }
  433. // install mouse handler
  434. if (!al_install_mouse()) {
  435. return state_errmsg_(self, "Error installing mouse.\n");
  436. }
  437. // install joystick
  438. if(!state_initjoystick(self)) {
  439. perror("Joysticks not started.");
  440. }
  441. /* Set up the audio system */
  442. self->audio = audio_init();
  443. if(!self->audio) {
  444. perror("Sound not started.");
  445. }
  446. // Use full screen mode if needed.
  447. if(self->fullscreen) {
  448. flags = ALLEGRO_FULLSCREEN | ALLEGRO_GENERATE_EXPOSE_EVENTS;
  449. } else {
  450. /* flags = ALLEGRO_FULLSCREEN_WINDOW | ALLEGRO_GENERATE_EXPOSE_EVENTS; */
  451. }
  452. // flags |= ALLEGRO_OPENGL;
  453. al_set_new_display_flags(flags);
  454. /* al_set_new_display_option(ALLEGRO_VSYNC, 2, ALLEGRO_SUGGEST); */
  455. // Create a window to display things on: 640x480 pixels.
  456. // self->display = al_create_display(1280, 960);
  457. self->display = al_create_display(SCREEN_W, SCREEN_H);
  458. if (!self->display) {
  459. return state_errmsg_(self, "Error creating display.\n");
  460. }
  461. // al_resize_display(self->display, SCREEN_W, SCREEN_H);
  462. // initialize the file finder, so we can start to load the data files
  463. if(!fifi_init()) {
  464. return state_errmsg_(self, "Could not find data folder!\n");
  465. }
  466. // initialize the resource storage so we can store the data files
  467. if(!store_init()) {
  468. return state_errmsg_(self, "Could not initialize data store.\n");
  469. }
  470. // Tuffy.ttf
  471. // "OpenBaskerville-0.0.53.otf"
  472. #define STATE_FONTNAME "GranaPadano.ttf"
  473. #define STATE_FONT_INDEX 20000
  474. if(!store_load_ttf_font(STATE_FONT_INDEX, "font/" STATE_FONTNAME, -16, 0)) {
  475. return state_errmsg_(self, "Error loading " STATE_FONTNAME);
  476. }
  477. self->font = store_get_font(STATE_FONT_INDEX);
  478. // fifi_loadfont(STATE_FONTNAME, 16, 0);
  479. if (!self->font) {
  480. return state_errmsg_(self, "Error loading " STATE_FONTNAME);
  481. }
  482. state_color_f(self, STATE_WHITE, 1, 1, 1, 1);
  483. state_color_f(self, STATE_BLACK, 0, 0, 0, 1);
  484. // Start the event queue to handle keyboard input and our timer
  485. self->queue = al_create_event_queue();
  486. state_eventsource(self, al_get_keyboard_event_source());
  487. state_eventsource(self, al_get_display_event_source(self->display));
  488. state_eventsource(self, al_get_mouse_event_source());
  489. state_eventsource(self, al_get_joystick_event_source());
  490. al_set_window_title(self->display, "Eruta!");
  491. // set up fps counter. Start with assuming we have 60 fps.
  492. self->fps = 60.0;
  493. self->fpstime = al_get_time();
  494. self->frames = 60;
  495. /* No active map yet. */
  496. state_active_map_id_(self, -1);
  497. /* Background color. */
  498. self->background_color = al_map_rgb(64,128,64);
  499. // set up camera
  500. self->camera = camera_new(-100, -100, SCREEN_W, SCREEN_H);
  501. if(!self->camera) {
  502. return state_errmsg_(self, "Out of memory when allocating camera.");
  503. }
  504. /* Set up Zori GUI. */
  505. {
  506. struct zori_style style;
  507. memset(&style, 0, sizeof(style));
  508. style.text.font = self->font;
  509. style.text.color = color_rgb(255,255,255);
  510. style.back.color = color_rgba(64,0,0, 191);
  511. if ( !ZORI_ID_OK_P(zori_start(&style)) ) {
  512. return state_errmsg_(self, "Out of memory when allocating GUI.");
  513. }
  514. }
  515. /* Set up console. */
  516. {
  517. struct zori_style style;
  518. memset(&style, 0, sizeof(style));
  519. style.text.font = self->font;
  520. style.text.color = color_rgb(255,255,255);
  521. style.back.color = color_rgba(64,0,0, 191);
  522. Rebox bounds = { {20, 20} , {600, 400} };
  523. self->console = zori_console_new(1, &bounds, &style);
  524. if(!self->console) {
  525. return state_errmsg_(self, "Out of memory when allocating console.");
  526. }
  527. }
  528. zori_console_puts(self->console, "Zori Console started ok!");
  529. // set up ruby callback for console commands
  530. zori_console_command_(self->console, rh_run_console_command, self->ruby);
  531. // set up logging to console
  532. monolog_add_logger(self->console, &state_console_logger);
  533. /* Initialize Area. */
  534. self->area = area_new();
  535. /* Initialize sprite list. */
  536. self->sprites = spritelist_new();
  537. /* Show all by default. */
  538. self->show_area = TRUE;
  539. self->show_fps = TRUE;
  540. self->show_graph= TRUE;
  541. return self;
  542. }
  543. /** Sets the state's busy status to false */
  544. BOOL state_done(State * state) {
  545. state->busy = FALSE;
  546. return state->busy;
  547. }
  548. /** Returns true if the state is busy false if not. */
  549. BOOL state_busy(State * self) {
  550. return self->busy;
  551. }
  552. /* Scales and moves the display to achieve resolution independence. */
  553. void state_scale_display(State * self) {
  554. int real_w = al_get_display_width(self->display);
  555. int real_h = al_get_display_height(self->display);
  556. int scale_x = real_w / SCREEN_W;
  557. int scale_y = real_h / SCREEN_H;
  558. int scale = (scale_x < scale_y) ? scale_x : scale_y;
  559. int offset_x= (real_w - (SCREEN_W * scale)) / 2;
  560. int offset_y= (real_h - (SCREEN_H * scale)) / 2;
  561. /*
  562. al_draw_textf(state_font(self), COLOR_WHITE,
  563. 100, 100, 0, "SCALE: w: %d, h: %d, sx: %d, sy: %d, s: %d, ox:%d, oy:%d",
  564. real_w, real_h, scale_x, scale_y, scale, offset_x, offset_y);
  565. */
  566. ALLEGRO_TRANSFORM transform;
  567. al_identity_transform(&transform);
  568. /* Now draw black bars to cover the usused areas. */
  569. if (offset_y > 0) {
  570. al_draw_filled_rectangle(-offset_x , -offset_y, real_w, 0, al_map_rgb(0,0,0));
  571. al_draw_filled_rectangle(-offset_x , SCREEN_H, real_w, SCREEN_H+offset_y, al_map_rgb(0,0,0));
  572. }
  573. if (offset_x > 0) {
  574. al_draw_filled_rectangle(-offset_x , -offset_y, 0, real_h, al_map_rgb(0,0,0));
  575. al_draw_filled_rectangle(SCREEN_W , -offset_y, SCREEN_W + offset_x, real_h, al_map_rgb(0,0,0));
  576. }
  577. al_scale_transform(&transform, scale, scale);
  578. al_translate_transform(&transform, offset_x, offset_y);
  579. al_use_transform(&transform);
  580. /* al_set_clipping_rectangle(offset_x, offset_y, SCREEN_W, SCREEN_H); */
  581. }
  582. /* Draws all inside the state that needs to be drawn. */
  583. void state_draw(State * self) {
  584. int layer;
  585. /* Draw background color if no map active. */
  586. if (!self->active_map) {
  587. al_clear_to_color(self->background_color);
  588. }
  589. /* Draw the layers of the map and area interleaved. */
  590. for (layer = 0; layer < TILEMAP_PANES; layer++) {
  591. if (self->active_map) {
  592. /* Shadows should be drawn *before* the blends, otherwise both won't
  593. * look good when combined with each other. The problem with that is,
  594. * though that shadows are then not cast on the sprites.
  595. * Perhaps sprites will need separate shadows???
  596. */
  597. tilemap_draw_layer_tiles(self->active_map, self->camera, layer);
  598. tilemap_draw_layer_shadows(self->active_map, self->camera, layer);
  599. tilemap_draw_layer_blends(self->active_map, self->camera, layer);
  600. }
  601. if (self->area && self->show_area) {
  602. area_draw_layer(self->area, self->camera, layer);
  603. }
  604. }
  605. /* Draw UI scene graph */
  606. if (self->show_graph) {
  607. zori_draw_all();
  608. }
  609. /* Draw the particles from the particle engine. */
  610. // alpsshower_draw(&shower, state_camera(state));
  611. /* Draw fps if needed. */
  612. if (self->show_fps) {
  613. al_draw_textf(state_font(self), COLOR_WHITE,
  614. 10, 10, 0, "FPS: %.0f", state_fps(self));
  615. }
  616. /* Draw the ui and the console (will autohide if not active). */
  617. zori_draw_all();
  618. state_scale_display(self);
  619. }
  620. /* Updates the state's display. */
  621. void state_flip_display(State * self) {
  622. al_flip_display();
  623. state_frames_update(self);
  624. }
  625. /* Updates the state's elements. */
  626. void state_update(State * self) {
  627. mrb_value mval;
  628. // alpsshower_update(&shower, state_frametime(state));
  629. if (self->active_map) {
  630. tilemap_update(self->active_map, state_frametime(self));
  631. }
  632. if (self->area) {
  633. area_update(self->area, state_frametime(self));
  634. }
  635. camera_update(self->camera);
  636. // call ruby update callback
  637. callrb_on_update(self);
  638. // Update the scene graph (after the Ruby upate so anty ruby side-changes take
  639. // effect immediately.
  640. scegra_update(state_frametime(self));
  641. zori_update(state_frametime(self));
  642. }
  643. /** Polls the state's event queue, and gets the next event and stores it in
  644. * event. if it is available. Returns true if there is an event of false if
  645. * not.
  646. */
  647. int state_poll(State * state, ALLEGRO_EVENT * event) {
  648. return al_get_next_event(state->queue, event);
  649. }
  650. /** Polls the state's event queue, and gets the next event and returns it.
  651. * returns nul if out of memory or no event was available.
  652. * You must free the result of this function with event_free
  653. */
  654. ALLEGRO_EVENT * state_pollnew(State * state) {
  655. ALLEGRO_EVENT event, * result;
  656. if(state_poll(state, &event)) {
  657. result = event_alloc();
  658. if(!result) return NULL;
  659. (*result) = event; // copy data
  660. return result; // return pointer
  661. }
  662. return NULL;
  663. }
  664. /** Return the state's default font. */
  665. ALLEGRO_FONT * state_font(State * state) {
  666. if(!state) return NULL;
  667. return state->font;
  668. }
  669. /** Call this every frame to update the FPS and frames value */
  670. void state_frames_update(State * state) {
  671. double now = al_get_time();
  672. state->frames++;
  673. if((now - state->fpstime) > 1.0) {
  674. double realfps;
  675. /* Measure only last second of frames, which means FPS gets updated every second or so. */
  676. realfps = ((double)state->frames) / (now - state->fpstime);
  677. /* Display and use a rounded value for FPS, the number after the comma is normally due to jitter anyway. */
  678. state->fps = floor(realfps + 0.5);
  679. /* A little trick, to prefent jerkyness,
  680. * keep half the frames; and half the time */
  681. state->frames = state->frames / 2;
  682. state->fpstime = now - 0.5;
  683. }
  684. }
  685. /** Returns the amount of frames rendered during this second. */
  686. int state_frames(State * state) {
  687. return state->frames;
  688. }
  689. /** Returns the FPS value. */
  690. double state_fps(State * state) {
  691. return state->fps;
  692. }
  693. /** Returns the Frame time value. */
  694. double state_frametime(State * state) {
  695. if( state->fps < 20.0) return 1.0 / 20.0;
  696. return 1.0 / state->fps;
  697. }
  698. /** Returns the camera of the state. */
  699. Camera * state_camera(State * state) {
  700. if(!state) return NULL;
  701. return state->camera;
  702. }
  703. /* Get display state */
  704. int global_state_show_fps() {
  705. State * state = state_get();
  706. if (!state) return FALSE;
  707. return state->show_fps;
  708. }
  709. /* Set display state */
  710. int global_state_show_fps_(int show) {
  711. State * state = state_get();
  712. if (!state) return FALSE;
  713. return state->show_fps = show;
  714. }
  715. /* Get display state */
  716. int global_state_show_graph() {
  717. State * state = state_get();
  718. if (!state) return FALSE;
  719. return state->show_graph;
  720. }
  721. /* Set display state */
  722. int global_state_show_graph_(int show) {
  723. State * state = state_get();
  724. if (!state) return FALSE;
  725. return state->show_graph = show;
  726. }
  727. /* Get display state */
  728. int global_state_show_area() {
  729. State * state = state_get();
  730. if (!state) return FALSE;
  731. return state->show_area;
  732. }
  733. /* Set display state */
  734. int global_state_show_area_(int show) {
  735. State * state = state_get();
  736. if (!state) return FALSE;
  737. return state->show_area = show;
  738. }
  739. /* Get display state of physics */
  740. int global_state_show_physics() {
  741. State * state = state_get();
  742. if (!state) return FALSE;
  743. return area_draw_physics(state->area);
  744. }
  745. /* Set display state of physics */
  746. int global_state_show_physics_(int show) {
  747. State * state = state_get();
  748. if (!state) return FALSE;
  749. area_draw_physics_(state->area, show);
  750. return show;
  751. }
  752. /* Core functionality of Eruta, implemented on the state. */
  753. /* Ideas about starting the game and progressing
  754. * Normally, the game will have different modes. The game will start in
  755. * intro mode, which automatically changes into main menu mode.
  756. * From main menu mode a game may be loaded or a new game may be started.
  757. *
  758. * When the game starts, the generic startup and settings scripts must be loaded.
  759. * They influence the design of the main menu.
  760. *
  761. * To begin, we must implement the new game start. When a new game is started,
  762. * the game start script is loaded. Then, unless instructed differently,
  763. * map number 0001 is loaded. As always, when a map is loaded,
  764. * the map's corresponding script is loaded. The game has an area of "savable"
  765. * data which is initialized either by loading the game or by the new game script.
  766. *
  767. * Before the game is saved, the save game script is loaded. Likewise before
  768. * the game is loaded the load game script is loaded.
  769. *
  770. * Once the game is running, the main game script is loaded and call-backs
  771. * are used to communicate with it. This is the mechanism that allows part of the game
  772. * to be implemented in script.
  773. *
  774. * Needed scripts so far: start.mrb, newgame.mrb, loadgame.mrb, savegame.mrb,
  775. * main.mrb, and one map_0001.mrb, etc for every map. Other scripts can be loaded by
  776. * these scripts for modulization, but only from the script directory.
  777. *
  778. */
  779. /* Preloads a tile map from the given vpath. Returns the loaded map, or
  780. NULL if not loaded.
  781. Tilemap * state_preloadmap_vpath(State * state, const char * vpath) {
  782. return NULL;
  783. }
  784. */
  785. /* Preloads a tile map with the given map number. Returns the loaded map, or
  786. NULL if not loaded.
  787. Tilemap * state_preloadmap_index(State * state, int index) {
  788. return NULL;
  789. }
  790. */
  791. /* Tints a layer of the sprite that belongs to a thing.*/
  792. int state_thing_tint_layer
  793. (State * state, int thing_index, int layer_index, int r, int g, int b, int a) {
  794. Thing * thing = state_thing(state, thing_index);
  795. Color color = al_map_rgba(r, g, b, a);
  796. if (!thing) { return -1; }
  797. thing_tint_layer(thing, layer_index, color);
  798. return 0;
  799. }
  800. /* Transforms a mask color of an image in storage into an alpha. */
  801. int state_image_mask_to_alpha(State * state, int store_index, int r, int g, int b) {
  802. Image * image = store_get_bitmap(store_index);
  803. Color color = al_map_rgb(r, g, b);
  804. (void) state;
  805. if (!image) return -1;
  806. al_convert_mask_to_alpha(image, color);
  807. return store_index;
  808. }
  809. /* Transforms an image in storage where the average is assigned to the alpha value. */
  810. int state_image_average_to_alpha(State * state, int store_index, int r, int g, int b) {
  811. Image * image = store_get_bitmap(store_index);
  812. Color color = al_map_rgb(r, g, b);
  813. (void) state;
  814. if (!image) return -1;
  815. draw_convert_average_to_alpha(image, color);
  816. return store_index;
  817. }
  818. /* Returns the first unused thing ID that is greater than minimum. */
  819. int state_get_unused_thing_id() {
  820. return area_get_unused_thing_id(state_area(state_get()));
  821. }
  822. /* Returns the first unused sprite ID that is greater than minimum. */
  823. int state_get_unused_sprite_id() {
  824. return spritelist_get_unused_sprite_id(state_sprites(state_get()));
  825. }
  826. /** Deletes a sprite from the sprite list of the state. */
  827. int state_delete_sprite(int index) {
  828. return spritelist_delete_sprite(state_sprites(state_get()), index);
  829. }
  830. /** Deletes a thing from the things of the state's area. */
  831. int state_delete_thing(int index) {
  832. return area_delete_thing(state_area(state_get()), index);
  833. }