Mercurial > molko
changeset 162:629f55f3961e
core: rework states
author | David Demelier <markand@malikania.fr> |
---|---|
date | Sun, 18 Oct 2020 12:01:59 +0200 |
parents | 31d7f23c0588 |
children | 4bbfcd9180a8 |
files | libadventure/CMakeLists.txt libadventure/adventure/assets/fonts/cubic.ttf libadventure/adventure/mainmenu_state.c libadventure/adventure/mainmenu_state.h libadventure/adventure/panic_state.c libadventure/adventure/panic_state.h libadventure/adventure/splashscreen_state.c libadventure/adventure/splashscreen_state.h libadventure/adventure/state/mainmenu.c libadventure/adventure/state/mainmenu.h libadventure/adventure/state/panic.c libadventure/adventure/state/panic.h libadventure/adventure/state/splashscreen.c libadventure/adventure/state/splashscreen.h libcore/CMakeLists.txt libcore/core/game.c libcore/core/panic.c libcore/core/state.c libcore/core/state.h librpg/rpg/map_state.c molko/main.c |
diffstat | 21 files changed, 941 insertions(+), 727 deletions(-) [+] |
line wrap: on
line diff
--- a/libadventure/CMakeLists.txt Sat Oct 17 10:12:41 2020 +0200 +++ b/libadventure/CMakeLists.txt Sun Oct 18 12:01:59 2020 +0200 @@ -19,19 +19,24 @@ project(libadventure) set( + STATE_SOURCES + ${libadventure_SOURCE_DIR}/adventure/state/mainmenu.c + ${libadventure_SOURCE_DIR}/adventure/state/mainmenu.h + ${libadventure_SOURCE_DIR}/adventure/state/panic.c + ${libadventure_SOURCE_DIR}/adventure/state/panic.h + ${libadventure_SOURCE_DIR}/adventure/state/splashscreen.c + ${libadventure_SOURCE_DIR}/adventure/state/splashscreen.h +) + +set( SOURCES - ${libadventure_SOURCE_DIR}/adventure/mainmenu_state.c - ${libadventure_SOURCE_DIR}/adventure/mainmenu_state.h - ${libadventure_SOURCE_DIR}/adventure/panic_state.c - ${libadventure_SOURCE_DIR}/adventure/panic_state.h - ${libadventure_SOURCE_DIR}/adventure/splashscreen_state.c - ${libadventure_SOURCE_DIR}/adventure/splashscreen_state.h ${libadventure_SOURCE_DIR}/adventure/trace_hud.c ${libadventure_SOURCE_DIR}/adventure/trace_hud.h ) set( ASSETS + ${libadventure_SOURCE_DIR}/adventure/assets/fonts/cubic.ttf ${libadventure_SOURCE_DIR}/adventure/assets/fonts/lato.ttf ${libadventure_SOURCE_DIR}/adventure/assets/fonts/teutonic.ttf ${libadventure_SOURCE_DIR}/adventure/assets/fonts/pirata-one.ttf @@ -42,7 +47,9 @@ molko_define_library( TARGET libadventure - SOURCES ${SOURCES} + SOURCES + ${STATE_SOURCES} + ${SOURCES} ASSETS ${ASSETS} LIBRARIES libcore libui librpg PUBLIC_INCLUDES @@ -50,3 +57,4 @@ ) source_group(adventure FILES ${SOURCES}) +source_group(adventure/state FILES ${STATE_SOURCES})
--- a/libadventure/adventure/mainmenu_state.c Sat Oct 17 10:12:41 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,222 +0,0 @@ -/* - * mainmenu_state.c -- game main menu - * - * Copyright (c) 2020 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <assert.h> -#include <stdlib.h> -#include <string.h> - -#include <core/event.h> -#include <core/font.h> -#include <core/game.h> -#include <core/image.h> -#include <core/painter.h> -#include <core/panic.h> -#include <core/state.h> -#include <core/sys.h> -#include <core/texture.h> -#include <core/window.h> - -#include <adventure/assets/fonts/pirata-one.h> -#include <adventure/assets/maps/overworld.h> -#include <adventure/assets/tilesets/world.h> -#include <adventure/assets/sprites/john.h> - -#include <rpg/map_state.h> - -#include "mainmenu_state.h" -#include "splashscreen_state.h" - -#define SPEED 120 -#define SEC 1000 - -enum substate { - SUBSTATE_MOVING, - SUBSTATE_WAITING -}; - -static int x; -static int y; -static unsigned int selection; -static int destination; -static enum substate substate; -static struct texture image; -static struct texture tileset; - -/* Menu items. */ -static struct { - struct texture texture; - int x; - int y; -} items[3]; - -static void -enter(void) -{ - struct font font; - - if (!font_openmem(&font, fonts_pirata_one, sizeof (fonts_pirata_one), 30)) - panic(); - - substate = SUBSTATE_MOVING; - x = splashscreen_state_data.x; - y = splashscreen_state_data.y; - destination = window.h / 4; - - /* TODO: change continue color if no game exists. */ - font_render(&font, &items[0].texture, "New game"); - items[0].x = (window.w / 2) - (items[0].texture.w / 2); - items[0].y = window.h * 0.75; - - font_render(&font, &items[1].texture, "Continue"); - items[1].x = items[0].x; - items[1].y = items[0].y + items[0].texture.h; - - font_render(&font, &items[2].texture, "Quit"); - items[2].x = items[0].x; - items[2].y = items[1].y + items[1].texture.h; - - font_finish(&font); -} - -static void -new(void) -{ - /* Prepare map. */ - if (!map_data_openmem(&map_state_data.map.data, maps_overworld, sizeof (maps_overworld))) - panicf("Unable to open map 'test'"); - - // TODO: this is temporary. - if (!image_openmem(&tileset, tilesets_world, sizeof (tilesets_world))) - panic(); - - if (!map_init(&map_state_data.map.map, &map_state_data.map.data, &tileset)) - panic(); - - /* Prepare image and sprite. */ - if (!(image_openmem(&image, sprites_john, sizeof (sprites_john)))) - panic(); - - sprite_init(&map_state_data.player.sprite, &image, 48, 48); - game_switch(&map_state, false); -} - -static void -resume(void) -{ -} - -static void -quit(void) -{ - game_quit(); -} - -static void -perform(void) -{ - assert(selection < 3); - - static void (*handlers[])(void) = { - [0] = new, - [1] = resume, - [2] = quit - }; - - handlers[selection](); -} - -static void -handle(const union event *event) -{ - if (substate != SUBSTATE_WAITING) - return; - - switch (event->type) { - case EVENT_KEYDOWN: - switch (event->key.key) { - case KEY_UP: - selection = selection == 0 ? 2 : selection - 1; - break; - case KEY_DOWN: - selection = (selection + 1) % 3; - break; - case KEY_ENTER: - perform(); - default: - break; - } - break; - default: - break; - } -} - -static void -update(unsigned int ticks) -{ - switch (substate) { - case SUBSTATE_MOVING: - y -= SPEED * ticks / SEC; - - if (y <= destination) { - y = destination; - substate = SUBSTATE_WAITING; - } - - break; - default: - break; - } -} - -static void -draw(void) -{ - painter_set_color(0xffffffff); - painter_clear(); - texture_draw(&splashscreen_state_data.text, x, y); - - if (substate == SUBSTATE_WAITING) { - texture_draw(&items[0].texture, items[0].x, items[0].y); - texture_draw(&items[1].texture, items[1].x, items[1].y); - texture_draw(&items[2].texture, items[2].x, items[2].y); - - /* Selection cursor. */ - - /* TODO: a sword here. */ - painter_set_color(0x000000ff); - painter_draw_rectangle(items[selection].x - 30, - items[selection].y + 11, 15, 15); - } -} - -static void -leave(void) -{ - texture_finish(&items[0].texture); - texture_finish(&items[1].texture); - memset(items, 0, sizeof (items)); -} - -struct state mainmenu_state = { - .enter = enter, - .handle = handle, - .update = update, - .draw = draw, - .leave = leave -};
--- a/libadventure/adventure/mainmenu_state.h Sat Oct 17 10:12:41 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,32 +0,0 @@ -/* - * mainmenu_state.h -- game main menu - * - * Copyright (c) 2020 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MOLKO_MAINMENU_STATE_H -#define MOLKO_MAINMENU_STATE_H - -/** - * \file mainmenu_state.h - * \brief Game main menu. - */ - -/** - * \brief Main menu state. - */ -extern struct state mainmenu_state; - -#endif /* !MOLKO_MAINMENU_STATE_H */
--- a/libadventure/adventure/panic_state.c Sat Oct 17 10:12:41 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,228 +0,0 @@ -/* - * panic_state.c -- panic state - * - * Copyright (c) 2020 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <assert.h> -#include <stdio.h> -#include <stdlib.h> - -#include <core/error.h> -#include <core/event.h> -#include <core/font.h> -#include <core/game.h> -#include <core/painter.h> -#include <core/sys.h> -#include <core/texture.h> -#include <core/util.h> -#include <core/window.h> - -#include <rpg/map_state.h> - -#include <adventure/assets/fonts/lato.h> - -#include "panic_state.h" - -#define BACKGROUND 0x4f5070ff -#define FOREGROUND 0xffffffff - -#define SIZE 16 -#define PADDING 20 - -#define OUT "molko-adventure.txt" - -struct label { - const char *text; - struct texture texture; -}; - -static struct { - struct font font; -} data; - -static struct label headers[] = { - { .text = "An unrecoverable error occured and the game cannot continue." }, - { .text = "Please report the detailed error as provided below." }, -}; - -static struct label bottom[] = { - { .text = "Press <s> to save information and generate a core dump." }, - { .text = "Press <q> to quit without saving information." } -}; - -static struct label lerror; - -static void -die(const char *fmt, ...) -{ - assert(fmt); - - va_list ap; - - va_start(ap, fmt); - fprintf(stderr, "abort: "); - vfprintf(stderr, fmt, ap); - va_end(ap); - exit(1); -} - -static void -enter(void) -{ -} - -static void -dump(void) -{ - FILE *fp; - - if (!(fp = fopen(OUT, "w"))) - goto dump; - - /* Print various information. */ - fprintf(fp, "Molko's Adventure crash dump report\n"); - fprintf(fp, "== state map dump ==\n"); - fprintf(fp, "map:\n"); - fprintf(fp, " w %u\n", map_state_data.map.data.w); - fprintf(fp, " h %u\n", map_state_data.map.data.h); - fprintf(fp, "player:\n"); - fprintf(fp, " x: %u\n", map_state_data.player.x); - fprintf(fp, " y: %u\n", map_state_data.player.y); - fprintf(fp, "view:\n"); - fprintf(fp, " w: %u\n", map_state_data.view.w); - fprintf(fp, " h: %u\n", map_state_data.view.h); - fprintf(fp, " x: %u\n", map_state_data.view.x); - fprintf(fp, " y: %u\n", map_state_data.view.y); - -dump: - if (fp) - fclose(fp); - - abort(); -} - -static void -handle_keydown(const struct event_key *ev) -{ - assert(ev); - - switch (ev->key) { - case KEY_q: - game_quit(); - break; - case KEY_s: - dump(); - break; - default: - break; - } -} - -static void -handle(const union event *ev) -{ - assert(ev); - - switch (ev->type) { - case EVENT_KEYDOWN: - handle_keydown(&ev->key); - break; - default: - break; - } -} - -static void -generate(struct label labels[], size_t labelsz) -{ - assert(labels); - - for (size_t i = 0; i < labelsz; ++i) { - if (texture_ok(&labels[i].texture)) - continue; - - data.font.color = FOREGROUND; - font_render(&data.font, &labels[i].texture, labels[i].text); - - if (!texture_ok(&labels[i].texture)) - die("%s\n", error()); - } -} - -static void -update(unsigned int ticks) -{ - (void)ticks; - - lerror.text = error(); - - generate(headers, NELEM(headers)); - generate(&lerror, 1); - generate(bottom, NELEM(bottom)); -} - -static void -draw(void) -{ - int y = PADDING; - - painter_set_target(NULL); - painter_set_color(BACKGROUND); - painter_clear(); - - /* Header. */ - for (size_t i = 0; i < NELEM(headers); ++i) { - texture_draw(&headers[i].texture, PADDING, y); - y += headers[i].texture.h + 2; - } - - /* Error message. */ - texture_draw(&lerror.texture, PADDING, y + PADDING); - - /* Bottom. */ - y = window.h - PADDING; - y -= bottom[0].texture.h; - - for (size_t i = 0; i < NELEM(bottom); ++i) { - texture_draw(&bottom[i].texture, PADDING, y); - y -= bottom[i].texture.h + 2; - } -} - -static void -leave(void) -{ -} - -struct state panic_state = { - .enter = enter, - .handle = handle, - .update = update, - .draw = draw, - .leave = leave -}; - -void -panic_state_init(void) -{ - /* - * If the panic state can not be loaded we're unable to show any - * useful information to the screen so as last resort print them - * on the console. - */ - if (!(font_openmem(&data.font, fonts_lato, sizeof (fonts_lato), SIZE))) - die("%s", error()); -}
--- a/libadventure/adventure/panic_state.h Sat Oct 17 10:12:41 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,46 +0,0 @@ -/* - * panic_state.h -- panic state - * - * Copyright (c) 2020 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MOLKO_PANIC_STATE_H -#define MOLKO_PANIC_STATE_H - -/** - * \file panic_state.h - * \brief Panic state. - */ - -#include <core/state.h> - -/** - * \brief Global panic state structure. - */ -extern struct state panic_state; - -/** - * Call this function as early as possible to be able to use this state even on - * memory allocation errors. - * - * \note You must still initialize the system before. - * \see \ref core_init - * \see \ref ui_init - * \see \ref window_open - */ -void -panic_state_init(void); - -#endif /* !MOLKO_PANIC_STATE_H */
--- a/libadventure/adventure/splashscreen_state.c Sat Oct 17 10:12:41 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,100 +0,0 @@ -/* - * splashscreen_state.c -- splash screen state - * - * Copyright (c) 2020 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <core/font.h> -#include <core/game.h> -#include <core/image.h> -#include <core/painter.h> -#include <core/panic.h> -#include <core/state.h> -#include <core/sys.h> -#include <core/texture.h> -#include <core/window.h> - -#include <rpg/map.h> -#include <rpg/map_state.h> - -#include <adventure/assets/fonts/teutonic.h> - -#include "splashscreen_state.h" -#include "mainmenu_state.h" - -#define DELAY 2000 - -struct splashscreen_state_data splashscreen_state_data; - -static void -enter(void) -{ - struct font font = { - .color = 0x000000ff - }; - - if (!(font_openmem(&font, fonts_teutonic, sizeof (fonts_teutonic), 130))) - panic(); - if (!(font_render(&font, &splashscreen_state_data.text, "Molko's Adventure"))) - panic(); - - /* Compute position. */ - const unsigned int w = splashscreen_state_data.text.w; - const unsigned int h = splashscreen_state_data.text.h; - - splashscreen_state_data.x = (window.w / 2) - (w / 2); - splashscreen_state_data.y = (window.h / 2) - (h / 2); - - font_finish(&font); -} - -static void -leave(void) -{ - /* We don't delete the texture because it is used by mainmenu_state. */ -} - -static void -handle(const union event *event) -{ - (void)event; -} - -static void -update(unsigned int ticks) -{ - splashscreen_state_data.elapsed += ticks; - - if (splashscreen_state_data.elapsed >= DELAY) - game_switch(&mainmenu_state, false); -} - -static void -draw(void) -{ - painter_set_color(0xffffffff); - painter_clear(); - texture_draw(&splashscreen_state_data.text, - splashscreen_state_data.x, - splashscreen_state_data.y); -} - -struct state splashscreen_state = { - .enter = enter, - .leave = leave, - .handle = handle, - .update = update, - .draw = draw -};
--- a/libadventure/adventure/splashscreen_state.h Sat Oct 17 10:12:41 2020 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,44 +0,0 @@ -/* - * splashscreen_state.h -- splash screen state - * - * Copyright (c) 2020 David Demelier <markand@malikania.fr> - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef MOLKO_SPLASHSCREEN_ADVENTURE_H -#define MOLKO_SPLASHSCREEN_ADVENTURE_H - -/** - * \file splashscreen_state.h - * \brief Splash screen state. - */ - -#include <core/texture.h> - -/** - * \brief Data for splashscreen. - */ -extern struct splashscreen_state_data { - struct texture text; /*!< (+) Texture for the text. */ - int x; /*!< (+) Position in x. */ - int y; /*!< (+) Position in y. */ - unsigned int elapsed; /*!< (+) Time elapsed. */ -} splashscreen_state_data; /*!< (+) Global state data. */ - -/** - * \brief Splash screen state. - */ -extern struct state splashscreen_state; - -#endif /* !MOLKO_SPLASHSCREEN_ADVENTURE_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libadventure/adventure/state/mainmenu.c Sun Oct 18 12:01:59 2020 +0200 @@ -0,0 +1,207 @@ +/* + * mainmenu.c -- game main menu + * + * Copyright (c) 2020 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <assert.h> +#include <stdlib.h> +#include <string.h> + +#include <core/event.h> +#include <core/font.h> +#include <core/game.h> +#include <core/painter.h> +#include <core/panic.h> +#include <core/state.h> +#include <core/texture.h> +#include <core/util.h> +#include <core/window.h> + +#include <ui/align.h> +#include <ui/label.h> +#include <ui/theme.h> + +#include <adventure/assets/fonts/teutonic.h> +#include <adventure/assets/fonts/pirata-one.h> + +#include "mainmenu.h" + +struct mainmenu { + struct { + struct texture tex; + int x; + int y; + } texts[4]; + + unsigned int itemsel; /* Selected item. */ +}; + +static void +new(void) +{ + /* TODO: implement here. */ +} + +static void +resume(void) +{ + /* TODO: implement here. */ +} + +static void +quit(void) +{ + game_quit(); +} + +static void +perform(struct mainmenu *main) +{ + assert(main->itemsel < 3); + + static void (*handlers[])(void) = { + [0] = new, + [1] = resume, + [2] = quit + }; + + handlers[main->itemsel](); +} + +static void +init_title(struct mainmenu *main, struct font *font) +{ + if (!font_render(font, &main->texts[3].tex, "Molko's Adventure")) + panic(); + + /* Align header. */ + align(ALIGN_CENTER, &main->texts[3].x, NULL, main->texts[3].tex.w, main->texts[3].tex.h, + 0, 0, window.w, window.h); + + main->texts[3].y = main->texts[3].x; +} + +static void +init_items(struct mainmenu *main, struct font *font) +{ + if (!font_render(font, &main->texts[0].tex, "New") || + !font_render(font, &main->texts[1].tex, "Continue") || + !font_render(font, &main->texts[2].tex, "Quit")) + panic(); + + main->texts[0].x = (window.w / 2) - (main->texts[0].tex.w / 2); + main->texts[0].y = window.h * 0.75; + + main->texts[1].x = main->texts[0].x; + main->texts[1].y = main->texts[0].y + main->texts[0].tex.h; + + main->texts[2].x = main->texts[0].x; + main->texts[2].y = main->texts[1].y + main->texts[1].tex.h; +} + +static void +start(struct state *state) +{ + struct mainmenu *main; + struct font fonts[2]; + + /* Allocate the main menu data. */ + main = (state->data = ecalloc(1, sizeof (*main))); + + if (!font_openmem(&fonts[0], fonts_teutonic, sizeof (fonts_teutonic), 130) || + !font_openmem(&fonts[1], fonts_pirata_one, sizeof (fonts_pirata_one), 30)) + panic(); + + fonts[0].color = fonts[1].color = 0x000000ff; + fonts[0].style = fonts[1].style = FONT_STYLE_ANTIALIASED; + + init_title(main, &fonts[0]); + init_items(main, &fonts[1]); + + font_finish(&fonts[0]); + font_finish(&fonts[1]); +} + +static void +handle(struct state *state, const union event *event) +{ + struct mainmenu *main = state->data; + + switch (event->type) { + case EVENT_KEYDOWN: + switch (event->key.key) { + case KEY_UP: + main->itemsel = main->itemsel == 0 ? 2 : main->itemsel - 1; + break; + case KEY_DOWN: + main->itemsel = (main->itemsel + 1) % 3; + break; + case KEY_ENTER: + perform(main); + break; + default: + break; + } + break; + default: + break; + } +} + +static void +draw(struct state *state) +{ + struct mainmenu *main = state->data; + + painter_set_color(0xffffffff); + painter_clear(); + + for (size_t i = 0; i < NELEM(main->texts); ++i) + texture_draw(&main->texts[i].tex, main->texts[i].x, main->texts[i].y); + + /* TODO: a sword here. */ + painter_set_color(0x000000ff); + painter_draw_rectangle( + main->texts[main->itemsel].x - 30, + main->texts[main->itemsel].y + 11, 15, 15); +} + +static void +finish(struct state *state) +{ + struct mainmenu *main = state->data; + + if (!main) + return; + + for (size_t i = 0; i < NELEM(main->texts); ++i) + texture_finish(&main->texts[i].tex); + + free(main); + memset(state, 0, sizeof (*state)); +} + +void +mainmenu_state(struct state *state) +{ + assert(state); + + memset(state, 0, sizeof (*state)); + state->start = start; + state->handle = handle; + state->draw = draw; + state->finish = finish; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libadventure/adventure/state/mainmenu.h Sun Oct 18 12:01:59 2020 +0200 @@ -0,0 +1,41 @@ +/* + * mainmenu.h -- game main menu + * + * Copyright (c) 2020 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MOLKO_STATE_MAINMENU_H +#define MOLKO_STATE_MAINMENU_H + +/** + * \file mainmenu.h + * \brief Game main menu. + */ + +/** + * Create a state about the main game menu. + * + * \pre state != NULL + * \param state the state to initialize + * \post state->data is set internal data + * \post state->handle is set + * \post state->draw is set + * \post state->update is set + * \post state->finish is set + */ +void +mainmenu_state(struct state *state); + +#endif /* !MOLKO_STATE_PANIC_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libadventure/adventure/state/panic.c Sun Oct 18 12:01:59 2020 +0200 @@ -0,0 +1,225 @@ +/* + * panic_state.c -- panic state + * + * Copyright (c) 2020 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <stdnoreturn.h> +#include <string.h> + +#include <core/error.h> +#include <core/event.h> +#include <core/font.h> +#include <core/game.h> +#include <core/painter.h> +#include <core/panic.h> +#include <core/state.h> +#include <core/sys.h> +#include <core/texture.h> +#include <core/util.h> +#include <core/window.h> + +#include <ui/align.h> +#include <ui/theme.h> + +#include <rpg/map_state.h> + +#include "panic.h" + +#define BACKGROUND 0x4f5070ff +#define FOREGROUND 0xffffffff + +#define OUT "molko-adventure.txt" + +struct view { + struct { + struct texture tex; + int x; + int y; + } texts[4]; +}; + +static noreturn void +die(const char *fmt, ...) +{ + assert(fmt); + + va_list ap; + + va_start(ap, fmt); + fprintf(stderr, "abort: "); + vfprintf(stderr, fmt, ap); + va_end(ap); + abort(); + exit(1); +} + +static noreturn void +stop(void) +{ + die("%s", error()); +} + +static void +dump(void) +{ + FILE *fp; + + if ((fp = fopen(OUT, "w"))) { + /* TODO: add more info here. */ + fprintf(fp, "Molko's Adventure crash dump report\n"); + fclose(fp); + } + + abort(); +} + +static struct view * +init(void) +{ + struct theme *theme; + struct view *view; + struct font font; + + theme = theme_default(); + view = ecalloc(1, sizeof (*view)); + + /* Generate the texts. */ + font_shallow(&font, theme->fonts[THEME_FONT_INTERFACE]); + font.style = FONT_STYLE_ANTIALIASED, + font.color = FOREGROUND; + + if (!font_render(&font, &view->texts[0].tex, "An unrecoverable error occured and the game cannot continue.") || + !font_render(&font, &view->texts[1].tex, "Please report the detailed error as provided below.") || + !font_render(&font, &view->texts[2].tex, "Press <s> to save information and generate a core dump.") || + !font_render(&font, &view->texts[3].tex, "Press <q> to quit without saving information.")) + die("%s", error()); + + /* All align x the same. */ + for (size_t i = 0; i < NELEM(view->texts); ++i) + view->texts[i].x = theme->padding; + + /* Header (0-1). */ + view->texts[0].y = theme->padding; + view->texts[1].y = view->texts[0].y + view->texts[0].tex.h + theme->padding; + + /* Footer. (2-3). */ + view->texts[3].y = window.h - view->texts[2].tex.h - theme->padding; + view->texts[2].y = view->texts[3].y - view->texts[3].tex.h - theme->padding; + + return view; +} + +static void +handle_keydown(const struct event_key *ev) +{ + assert(ev); + + switch (ev->key) { + case KEY_q: + game_quit(); + break; + case KEY_s: + dump(); + break; + default: + break; + } +} + +static void +start(struct state *state) +{ + (void)state; + + /* We remove the panic handler to avoid infinite recursion. */ + panic_handler = stop; +} + +static void +handle(struct state *state, const union event *ev) +{ + assert(ev); + + (void)state; + + switch (ev->type) { + case EVENT_KEYDOWN: + handle_keydown(&ev->key); + break; + default: + break; + } +} + +static void +draw(struct state *state) +{ + struct theme *theme = theme_default(); + struct view *view = state->data; + struct texture tex; + struct font font; + int x, y; + + painter_set_color(BACKGROUND); + painter_clear(); + + for (size_t i = 0; i < NELEM(view->texts); ++i) + texture_draw(&view->texts[i].tex, view->texts[i].x, view->texts[i].y); + + /* The error is only available here. */ + font_shallow(&font, theme->fonts[THEME_FONT_INTERFACE]); + font.color = FOREGROUND; + font.style = FONT_STYLE_ANTIALIASED; + + if (!font_render(&font, &tex, error())) + die("%s\n", error()); + + align(ALIGN_LEFT, &x, &y, tex.w, tex.h, 0, 0, window.w, window.h); + + texture_draw(&tex, x + theme->padding, y); + texture_finish(&tex); +} + +static void +finish(struct state *state) +{ + struct view *view = state->data; + + if (!view) + return; + + for (size_t i = 0; i < NELEM(view->texts); ++i) + texture_finish(&view->texts[i].tex); + + free(view); + memset(state, 0, sizeof (*state)); +} + +void +panic_state(struct state *state) +{ + assert(state); + + memset(state, 0, sizeof (*state)); + state->data = init(); + state->start = start; + state->handle = handle; + state->draw = draw; + state->finish = finish; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libadventure/adventure/state/panic.h Sun Oct 18 12:01:59 2020 +0200 @@ -0,0 +1,38 @@ +/* + * panic_state.h -- panic state + * + * Copyright (c) 2020 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MOLKO_STATE_PANIC_H +#define MOLKO_STATE_PANIC_H + +/** + * \file panic.h + * \brief Panic state. + */ + +struct state; + +/** + * Create a state in case of panic. + * + * \pre state != NULL + * \param state the state to initialize + */ +void +panic_state(struct state *state); + +#endif /* !MOLKO_STATE_PANIC_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libadventure/adventure/state/splashscreen.c Sun Oct 18 12:01:59 2020 +0200 @@ -0,0 +1,122 @@ +/* + * splashscreen.c -- splash screen state + * + * Copyright (c) 2020 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <assert.h> +#include <stdlib.h> +#include <string.h> + +#include <core/font.h> +#include <core/game.h> +#include <core/image.h> +#include <core/painter.h> +#include <core/panic.h> +#include <core/state.h> +#include <core/sys.h> +#include <core/texture.h> +#include <core/util.h> +#include <core/window.h> + +#include <ui/align.h> + +#include <adventure/assets/fonts/cubic.h> + +#include "splashscreen.h" +#include "mainmenu.h" + +#define DELAY 3000 + +struct splashscreen { + struct texture tex; + int x; + int y; + struct state *next; + unsigned int elapsed; +}; + +static struct splashscreen * +init(struct state *next) +{ + struct splashscreen *splash; + struct font font; + + splash = ecalloc(1, sizeof (*splash)); + splash->next = next; + + if (!font_openmem(&font, fonts_cubic, sizeof (fonts_cubic), 80)) + panic(); + + font.color = 0x19332dff; + font.style = FONT_STYLE_ANTIALIASED; + + if (!font_render(&font, &splash->tex, "malikania")) + panic(); + + align(ALIGN_CENTER, &splash->x, &splash->y, splash->tex.w, splash->tex.h, + 0, 0, window.w, window.h); + font_finish(&font); + + return splash; +} + +static void +update(struct state *state, unsigned int ticks) +{ + struct splashscreen *splash = state->data; + + splash->elapsed += ticks; + + if (splash->elapsed >= DELAY) + game_switch(splash->next, false); +} + +static void +draw(struct state *state) +{ + struct splashscreen *splash = state->data; + + painter_set_color(0xffffffff); + painter_clear(); + texture_draw(&splash->tex, splash->x, splash->y); +} + +static void +finish(struct state *state) +{ + struct splashscreen *splash = state->data; + + if (!splash) + return; + + texture_finish(&splash->tex); + + free(splash); + memset(state, 0, sizeof (*state)); +} + +void +splashscreen_state(struct state *state, struct state *next) +{ + assert(state); + assert(next); + + memset(state, 0, sizeof (*state)); + state->data = init(next); + state->update = update; + state->draw = draw; + state->finish = finish; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libadventure/adventure/state/splashscreen.h Sun Oct 18 12:01:59 2020 +0200 @@ -0,0 +1,42 @@ +/* + * splashscreen.h -- splash screen state + * + * Copyright (c) 2020 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MOLKO_STATE_SPLASHSCREEN_H +#define MOLKO_STATE_SPLASHSCREEN_H + +/** + * \file splashscreen.h + * \brief Splash screen state. + */ + +/** + * Create a state for showing a splashcreen. + * + * \pre state != NULL + * \pre next != NULL + * \param state the state to initialize + * \param next the next state once it's finished + * \post state->data is set internal data + * \post state->draw is set + * \post state->update is set + * \post state->finish is set + */ +void +splashscreen_state(struct state *state, struct state *next); + +#endif /* !MOLKO_STATE_SPLASHSCREEN_H */
--- a/libcore/CMakeLists.txt Sat Oct 17 10:12:41 2020 +0200 +++ b/libcore/CMakeLists.txt Sun Oct 18 12:01:59 2020 +0200 @@ -63,6 +63,7 @@ ${libcore_SOURCE_DIR}/core/sound.h ${libcore_SOURCE_DIR}/core/sprite.c ${libcore_SOURCE_DIR}/core/sprite.h + ${libcore_SOURCE_DIR}/core/state.c ${libcore_SOURCE_DIR}/core/state.h ${libcore_SOURCE_DIR}/core/sys.c ${libcore_SOURCE_DIR}/core/sys.h
--- a/libcore/core/game.c Sat Oct 17 10:12:41 2020 +0200 +++ b/libcore/core/game.c Sun Oct 18 12:01:59 2020 +0200 @@ -32,47 +32,63 @@ assert(state); if (quick) { + if (game.state_next) + state_finish(game.state_next); + game.state_next = NULL; game.state = state; - game.state->enter(); + state_start(game.state); } else game.state_next = state; } void -game_handle(const union event *event) +game_handle(const union event *ev) { - assert(event); + assert(ev); if (game.state && !(game.inhibit & INHIBIT_STATE_INPUT)) - game.state->handle(event); + state_handle(game.state, ev); } void game_update(unsigned int ticks) { - if (!(game.inhibit & INHIBIT_STATE_UPDATE)) { - /* Change state if any. */ - if (game.state_next) { - /* Inform the current state we're gonna leave it. */ - if (game.state) - game.state->leave(); + if (game.inhibit & INHIBIT_STATE_UPDATE) + return; + + /* Change state if any. */ + if (game.state_next) { + struct state *previous; + + /* Inform the current state we're gonna leave it. */ + if ((previous = game.state)) + state_end(previous); - game.state = game.state_next; - game.state->enter(); - game.state_next = NULL; - } + /* Change the state and tell we're starting it. */ + if ((game.state = game.state_next)) + state_start(game.state); + + game.state_next = NULL; - if (game.state) - game.state->update(ticks); + /* + * Only call finish at the end of the process because + * the user may still use resources from it during the + * transition. + */ + if (previous) + state_finish(previous); } + + if (game.state) + state_update(game.state, ticks); } void game_draw(void) { if (game.state && !(game.inhibit & INHIBIT_STATE_DRAW)) - game.state->draw(); + state_draw(game.state); painter_present(); } @@ -80,8 +96,15 @@ void game_quit(void) { - if (game.state && game.state->leave) - game.state->leave(); - - game.state = NULL; + /* Close the next state if any. */ + if (game.state_next) { + state_finish(game.state_next); + game.state_next = NULL; + } + + if (game.state) { + state_end(game.state); + state_finish(game.state); + game.state = NULL; + } }
--- a/libcore/core/panic.c Sat Oct 17 10:12:41 2020 +0200 +++ b/libcore/core/panic.c Sun Oct 18 12:01:59 2020 +0200 @@ -26,7 +26,8 @@ static noreturn void terminate(void) { - fprintf(stderr, "abort: %s", error()); + fprintf(stderr, "abort: %s\n", error()); + abort(); exit(1); }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libcore/core/state.c Sun Oct 18 12:01:59 2020 +0200 @@ -0,0 +1,76 @@ +/* + * state.c -- abstract state + * + * Copyright (c) 2020 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <assert.h> + +#include "state.h" + +void +state_start(struct state *state) +{ + assert(state); + + if (state->start) + state->start(state); +} + +void +state_handle(struct state *state, const union event *ev) +{ + assert(state); + assert(ev); + + if (state->handle) + state->handle(state, ev); +} + +void +state_update(struct state *state, unsigned int ticks) +{ + assert(state); + + if (state->update) + state->update(state, ticks); +} + +void +state_draw(struct state *state) +{ + assert(state); + + if (state->draw) + state->draw(state); +} + +void +state_end(struct state *state) +{ + assert(state); + + if (state->end) + state->end(state); +} + +void +state_finish(struct state *state) +{ + assert(state); + + if (state->finish) + state->finish(state); +}
--- a/libcore/core/state.h Sat Oct 17 10:12:41 2020 +0200 +++ b/libcore/core/state.h Sun Oct 18 12:01:59 2020 +0200 @@ -23,6 +23,13 @@ * \file state.h * \brief Abstract state. * \ingroup states + * + * The state module is a facility that allows changing game context with ease + * using a single \ref game_switch routine. + * + * The user creates any state required, set appropriate functions if needed and + * place them in the game using \ref game_switch. Then function \ref game_handle + * \ref game_update and finally \ref game_draw. */ union event; @@ -32,32 +39,117 @@ */ struct state { /** - * (+?) This function is called when the state is entered. + * (+&?) Optional user data. */ - void (*enter)(void); + void *data; /** - * (+?) This function is called when the state is about to be left. + * (+?) This function is called when the state is about to begin. + * + * \param state this state */ - void (*leave)(void); + void (*start)(struct state *state); /** * (+) This function is called for each event that happened. + * + * \param state this state + * \param ev the event */ - void (*handle)(const union event *); + void (*handle)(struct state *state, const union event *); /** * (+) Update the state. * * This function is called to update the game, with the number of * milliseconds since the last frame. + * + * \param state this state + * \param ev the event */ - void (*update)(unsigned int ticks); + void (*update)(struct state *state, unsigned int ticks); /** * (+) This function is supposed to draw the game. + * + * \param state this state */ - void (*draw)(void); + void (*draw)(struct state *state); + + /** + * (+?) This function is called when the state is about to be switched + * away from. + * + * This function is not called in case `quick` is set to true when + * calling \ref game_switch function. + * + * \param state this state + */ + void (*end)(struct state *state); + + /** + * (+?) This function is called to close resources if necessary. + * + * \param state the state + */ + void (*finish)(struct state *state); }; +/** + * Shortcut for state->start (if not NULL) + * + * \pre state != NULL + * \param state the state + */ +void +state_start(struct state *state); + +/** + * Shortcut for state->handle (if not NULL) + * + * \pre state != NULL + * \pre ev != NULL + * \param state the state + * \param ev the event + */ +void +state_handle(struct state *state, const union event *ev); + +/** + * Shortcut for state->update (if not NULL) + * + * \pre state != NULL + * \param state the state + * \param ticks elapsed milliseconds since last frame + */ +void +state_update(struct state *state, unsigned int ticks); + +/** + * Shortcut for state->draw (if not NULL) + * + * \pre state != NULL + * \param state the state + */ +void +state_draw(struct state *state); + +/** + * Shortcut for state->end (if not NULL) + * + * \pre state != NULL + * \param state the state + */ +void +state_end(struct state *state); + +/** + * Shortcut for state->finish (if not NULL) + * + * \pre state != NULL + * \param state the state + */ +void +state_finish(struct state *state); + #endif /* !MOLKO_STATE_H */
--- a/librpg/rpg/map_state.c Sat Oct 17 10:12:41 2020 +0200 +++ b/librpg/rpg/map_state.c Sun Oct 18 12:01:59 2020 +0200 @@ -126,8 +126,10 @@ } static void -enter(void) +start(struct state *st) { + (void)st; + /* Adjust map properties. */ struct map *m = &map_state_data.map.map; @@ -151,11 +153,6 @@ } static void -leave(void) -{ -} - -static void handle_keydown(const union event *event) { switch (event->key.key) { @@ -303,8 +300,10 @@ } static void -handle(const union event *event) +handle(struct state *st, const union event *event) { + (void)st; + switch (event->type) { case EVENT_KEYDOWN: handle_keydown(event); @@ -318,14 +317,18 @@ } static void -update(unsigned int ticks) +update(struct state *st, unsigned int ticks) { + (void)st; + move(ticks); } static void -draw(void) +draw(struct state *st) { + (void)st; + struct debug_report report = {0}; map_draw(&map_state_data.map.map, VIEW()->x, VIEW()->y); @@ -344,8 +347,7 @@ struct map_state_data map_state_data; struct state map_state = { - .enter = enter, - .leave = leave, + .start = start, .update = update, .handle = handle, .draw = draw
--- a/molko/main.c Sat Oct 17 10:12:41 2020 +0200 +++ b/molko/main.c Sun Oct 18 12:01:59 2020 +0200 @@ -24,6 +24,7 @@ #include <core/event.h> #include <core/game.h> #include <core/panic.h> +#include <core/state.h> #include <core/sys.h> #include <core/util.h> #include <core/window.h> @@ -33,12 +34,19 @@ #include <rpg/rpg.h> -#include <adventure/panic_state.h> -#include <adventure/splashscreen_state.h> +#include <adventure/state/panic.h> +#include <adventure/state/splashscreen.h> +#include <adventure/state/mainmenu.h> #define WINDOW_WIDTH 1280 #define WINDOW_HEIGHT 720 +static struct { + struct state splash; + struct state mainmenu; + struct state panic; +} states; + static jmp_buf panic_buf; static noreturn void @@ -61,14 +69,14 @@ */ /* Init unrecoverable panic state. */ - panic_state_init(); + panic_state(&states.panic); panic_handler = unrecoverable; - if (!theme_init()) - panic(); + /* Init states. */ + splashscreen_state(&states.splash, &states.mainmenu); + mainmenu_state(&states.mainmenu); - /* Default state is splash screen */ - game_switch(&splashscreen_state, true); + game_switch(&states.splash, true); } static void @@ -123,7 +131,7 @@ for (union event ev; event_poll(&ev); ) continue; - game_switch(&panic_state, true); + game_switch(&states.panic, true); run(); }