diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 142560e..b44de3d 100755 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -15,6 +15,7 @@ target_sources(microrpg PRIVATE ) # Subdirs +add_subdirectory(cutscene) add_subdirectory(entity) add_subdirectory(scene) add_subdirectory(platform) diff --git a/src/cutscene/CMakeLists.txt b/src/cutscene/CMakeLists.txt new file mode 100755 index 0000000..c37ed2e --- /dev/null +++ b/src/cutscene/CMakeLists.txt @@ -0,0 +1,11 @@ +# Copyright (c) 2025 Dominic Masters +# +# This software is released under the MIT License. +# https://opensource.org/licenses/MIT + +# Sources +target_sources(microrpg PRIVATE + cutscene.c + cutsceneitem.c + cutscenemode.c +) \ No newline at end of file diff --git a/src/cutscene/cutscene.c b/src/cutscene/cutscene.c new file mode 100644 index 0000000..373d1d2 --- /dev/null +++ b/src/cutscene/cutscene.c @@ -0,0 +1,49 @@ +/** + * Copyright (c) 2025 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#include "cutscene.h" +#include "game.h" + +void cutsceneInit() { + memset(&GAME.cutsceneSystem, 0, sizeof(GAME.cutsceneSystem)); +} + +void cutsceneStart(const cutscene_t *cutscene) { + GAME.cutsceneSystem.cutscene = cutscene; + GAME.cutsceneSystem.mode = CUTSCENE_MODE_INITIAL; + GAME.cutsceneSystem.currentItem = 0xFF;// Set to 0xFF so start wraps. + cutsceneNext(); +} + +void cutsceneTick() { + if(GAME.cutsceneSystem.cutscene == NULL) return; + + const cutsceneitem_t *item = ( + &GAME.cutsceneSystem.cutscene->items[GAME.cutsceneSystem.currentItem] + ); + cutsceneItemTick(item, &GAME.cutsceneSystem.data); +} + +void cutsceneNext() { + if(GAME.cutsceneSystem.cutscene == NULL) return; + + GAME.cutsceneSystem.currentItem++; + + // End of the cutscene? + if(GAME.cutsceneSystem.currentItem >= GAME.cutsceneSystem.cutscene->itemCount) { + GAME.cutsceneSystem.cutscene = NULL; + GAME.cutsceneSystem.currentItem = 0; + GAME.cutsceneSystem.mode = CUTSCENE_MODE_NONE; + return; + } + + // Start item. + const cutsceneitem_t *item = ( + &GAME.cutsceneSystem.cutscene->items[GAME.cutsceneSystem.currentItem] + ); + cutsceneItemStart(item, &GAME.cutsceneSystem.data); +} \ No newline at end of file diff --git a/src/cutscene/cutscene.h b/src/cutscene/cutscene.h index 07bb59d..54d2a38 100755 --- a/src/cutscene/cutscene.h +++ b/src/cutscene/cutscene.h @@ -6,22 +6,41 @@ */ #pragma once -#include "microrpg.h" - -#define CUTSCENE_ITEM_NULL 0 -#define CUTSCENE_ITEM_TEXTBOX 1 -#define CUTSCENE_ITEM_CALLBACK 2 +#include "cutsceneitem.h" +#include "cutscenemode.h" typedef struct { - uint8_t type; - - union { - const char *textbox; - void (*callback)(void);// TODO: Bring entity data across. - }; -} cutsceneitem_t; - -typedef struct { - cutsceneitem_t *items; + const cutsceneitem_t *items; uint8_t itemCount; -} cutscene_t; \ No newline at end of file +} cutscene_t; + +typedef struct { + const cutscene_t *cutscene; + uint8_t currentItem; + + // Data (used by the current item). + cutsceneitemdata_t data; + cutscenemode_t mode; +} cutscenesystem_t; + +/** + * Initialize the cutscene system. + */ +void cutsceneInit(); + +/** + * Start a cutscene. + * + * @param cutscene Pointer to the cutscene to start. + */ +void cutsceneStart(const cutscene_t *cutscene); + +/** + * Advance to the next item in the cutscene. + */ +void cutsceneNext(); + +/** + * Update the cutscene system for one tick. + */ +void cutsceneTick(); \ No newline at end of file diff --git a/src/cutscene/cutscenecallback.h b/src/cutscene/cutscenecallback.h new file mode 100644 index 0000000..3f22871 --- /dev/null +++ b/src/cutscene/cutscenecallback.h @@ -0,0 +1,11 @@ +/** + * Copyright (c) 2025 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#pragma once +#include "microrpg.h" + +typedef void (*cutscenecallback_t)(void); \ No newline at end of file diff --git a/src/cutscene/cutsceneitem.c b/src/cutscene/cutsceneitem.c new file mode 100644 index 0000000..5a3e548 --- /dev/null +++ b/src/cutscene/cutsceneitem.c @@ -0,0 +1,48 @@ +/** + * Copyright (c) 2025 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#include "cutsceneitem.h" +#include "cutscene.h" + +void cutsceneItemStart(const cutsceneitem_t *item, cutsceneitemdata_t *data) { + switch(item->type) { + case CUTSCENE_ITEM_TEXT: + break; + + case CUTSCENE_ITEM_WAIT: + data->wait = item->wait; + break; + + case CUTSCENE_ITEM_CALLBACK: + if(item->callback != NULL) item->callback(); + break; + + default: + break; + } +} + +void cutsceneItemTick(const cutsceneitem_t *item, cutsceneitemdata_t *data) { + switch(item->type) { + case CUTSCENE_ITEM_TEXT: + break; + + case CUTSCENE_ITEM_CALLBACK: + break; + + case CUTSCENE_ITEM_WAIT: + data->wait--; + if(data->wait <= 0) { + // Wait is over, proceed to next item. + cutsceneNext(); + } + break; + + default: + break; + } +} \ No newline at end of file diff --git a/src/cutscene/cutsceneitem.h b/src/cutscene/cutsceneitem.h new file mode 100644 index 0000000..bb80611 --- /dev/null +++ b/src/cutscene/cutsceneitem.h @@ -0,0 +1,47 @@ +/** + * Copyright (c) 2025 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#pragma once +#include "cutscenewait.h" +#include "cutscenecallback.h" +#include "cutscenetext.h" + +#define CUTSCENE_ITEM_NULL 0 +#define CUTSCENE_ITEM_TEXT 1 +#define CUTSCENE_ITEM_CALLBACK 2 +#define CUTSCENE_ITEM_WAIT 3 + +typedef struct cutsceneitem_s { + uint8_t type; + + // Arguments/Data that will be used when this item is invoked. + union { + cutscenetext_t text; + cutscenecallback_t callback; + cutscenewait_t wait; + }; +} cutsceneitem_t; + +typedef union { + cutscenewaitdata_t wait; +} cutsceneitemdata_t; + +/** + * Start the given cutscene item. + * + * @param item The cutscene item to start. + * @param data The cutscene item data storage. + */ +void cutsceneItemStart(const cutsceneitem_t *item, cutsceneitemdata_t *data); + +/** + * Tick the given cutscene item (one frame). + * + * @param item The cutscene item to tick. + * @param data The cutscene item data storage. + */ +void cutsceneItemTick(const cutsceneitem_t *item, cutsceneitemdata_t *data); \ No newline at end of file diff --git a/src/cutscene/cutscenemode.c b/src/cutscene/cutscenemode.c new file mode 100644 index 0000000..496c08f --- /dev/null +++ b/src/cutscene/cutscenemode.c @@ -0,0 +1,20 @@ +/** + * Copyright (c) 2025 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#include "cutscenemode.h" +#include "game.h" + +bool_t cutsceneModeIsInputAllowed() { + switch(GAME.cutsceneSystem.mode) { + case CUTSCENE_MODE_FULL_FREEZE: + case CUTSCENE_MODE_INPUT_FREEZE: + return false; + + default: + return true; + } +} \ No newline at end of file diff --git a/src/cutscene/cutscenemode.h b/src/cutscene/cutscenemode.h new file mode 100644 index 0000000..a66ce10 --- /dev/null +++ b/src/cutscene/cutscenemode.h @@ -0,0 +1,33 @@ +/** + * Copyright (c) 2025 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#pragma once +#include "microrpg.h" + +// Mode 0, Assume no cutscene is active. +#define CUTSCENE_MODE_NONE 0 + +// Mode 1, assume that the cutscene is controlling all gameplay (full freeze). +#define CUTSCENE_MODE_FULL_FREEZE 1 + +// Mode 2, assume that the cutscene is simply stopping regular player input. +#define CUTSCENE_MODE_INPUT_FREEZE 2 + +// Mode 3, assume that the cutscene is not affecting gameplay directly. +#define CUTSCENE_MODE_GAMEPLAY 3 + +// Default mode for all cutscenes. +#define CUTSCENE_MODE_INITIAL CUTSCENE_MODE_INPUT_FREEZE + +typedef uint8_t cutscenemode_t; + +/** + * Check if input is allowed in the current cutscene mode. + * + * @return true if input is allowed, false otherwise. + */ +bool_t cutsceneModeIsInputAllowed(); \ No newline at end of file diff --git a/src/cutscene/cutscenetext.h b/src/cutscene/cutscenetext.h new file mode 100644 index 0000000..77afc50 --- /dev/null +++ b/src/cutscene/cutscenetext.h @@ -0,0 +1,11 @@ +/** + * Copyright (c) 2025 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#pragma once +#include "microrpg.h" + +typedef const char *cutscenetext_t; \ No newline at end of file diff --git a/src/cutscene/cutscenewait.h b/src/cutscene/cutscenewait.h new file mode 100644 index 0000000..f57cb6a --- /dev/null +++ b/src/cutscene/cutscenewait.h @@ -0,0 +1,12 @@ +/** + * Copyright (c) 2025 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#pragma once +#include "microrpg.h" + +typedef uint16_t cutscenewait_t; +typedef uint16_t cutscenewaitdata_t; \ No newline at end of file diff --git a/src/cutscene/scene/testcutscene.h b/src/cutscene/scene/testcutscene.h new file mode 100755 index 0000000..7794d4d --- /dev/null +++ b/src/cutscene/scene/testcutscene.h @@ -0,0 +1,21 @@ +/** + * Copyright (c) 2025 Dominic Masters + * + * This software is released under the MIT License. + * https://opensource.org/licenses/MIT + */ + +#pragma once +#include "cutscene/cutscene.h" + +static void testCutsceneTest() { +} + +static const cutsceneitem_t TEST_CUTSCENE_ITEMS[] = { + { .type = CUTSCENE_ITEM_WAIT, .wait = 1 * GAME_TIME_TICKS_PER_SECOND } +}; + +static const cutscene_t TEST_CUTSCENE = { + .items = TEST_CUTSCENE_ITEMS, + .itemCount = sizeof(TEST_CUTSCENE_ITEMS) / sizeof(cutsceneitem_t) +}; \ No newline at end of file diff --git a/src/cutscene/testcutscene.h b/src/cutscene/testcutscene.h deleted file mode 100755 index 0727e35..0000000 --- a/src/cutscene/testcutscene.h +++ /dev/null @@ -1,17 +0,0 @@ -/** - * Copyright (c) 2025 Dominic Masters - * - * This software is released under the MIT License. - * https://opensource.org/licenses/MIT - */ - -#pragma once -#include "cutscene.h" - -static void testCutsceneTest() { - abort(); -} - -cutsceneitem_t TEST_CUTSCENE_ITEMS[] = { - { .type = CUTSCENE_ITEM_CALLBACK, .callback = testCutsceneTest } -}; \ No newline at end of file diff --git a/src/entity/entity.c b/src/entity/entity.c index 7e8ce0c..16db805 100755 --- a/src/entity/entity.c +++ b/src/entity/entity.c @@ -31,7 +31,7 @@ void entityTick(entity_t *entity) { } // Let entities move (if they do) - if(entity->type == ENTITY_TYPE_PLAYER) { + if(entity->type == ENTITY_TYPE_PLAYER && cutsceneModeIsInputAllowed()) { playerTickInput(entity); } } diff --git a/src/entity/sign.c b/src/entity/sign.c index 9fd6504..dbe7cb7 100755 --- a/src/entity/sign.c +++ b/src/entity/sign.c @@ -9,5 +9,6 @@ #include "entity.h" void signInteract(entity_t *entity) { - abort(); + if(entity->sign.cutscene == NULL) return; + cutsceneStart(entity->sign.cutscene); } \ No newline at end of file diff --git a/src/entity/sign.h b/src/entity/sign.h index 18e4d00..378cd86 100755 --- a/src/entity/sign.h +++ b/src/entity/sign.h @@ -6,12 +6,12 @@ */ #pragma once -#include "microrpg.h" +#include "cutscene/cutscene.h" typedef struct entity_s entity_t; typedef struct sign_s { - void *nothing; + const cutscene_t *cutscene; } sign_t; /** diff --git a/src/game.c b/src/game.c index 743ce41..191fb16 100755 --- a/src/game.c +++ b/src/game.c @@ -6,22 +6,28 @@ */ #include "game.h" +#include "cutscene/cutscene.h" +#include "cutscene/scene/testcutscene.h" game_t GAME; void gameInit() { memset(&GAME, 0, sizeof(GAME)); + cutsceneInit(); + entityInit(&GAME.player, ENTITY_TYPE_PLAYER); entityInit(&GAME.overworld.map.entities[0], ENTITY_TYPE_SIGN); GAME.overworld.map.entities[0].position.x = 5; GAME.overworld.map.entities[0].position.y = 5; + GAME.overworld.map.entities[0].sign.cutscene = &TEST_CUTSCENE; GAME.scene = SCENE_OVERWORLD; } void gameTick() { gameTimeTick(&GAME.time); + cutsceneTick(); sceneTick(); } \ No newline at end of file diff --git a/src/game.h b/src/game.h index f8de64d..ddcc866 100755 --- a/src/game.h +++ b/src/game.h @@ -9,6 +9,7 @@ #include "entity/entity.h" #include "world/map.h" #include "scene/scene.h" +#include "cutscene/cutscene.h" #include "gametime.h" #define GAME_SCENE_INITIAL 0 @@ -18,6 +19,7 @@ typedef struct game_s { scene_t scene; entity_t player; gametime_t time; + cutscenesystem_t cutsceneSystem; union { struct { diff --git a/src/platform/raylib/platform.c b/src/platform/raylib/platform.c index e8bd949..83376c8 100644 --- a/src/platform/raylib/platform.c +++ b/src/platform/raylib/platform.c @@ -72,7 +72,7 @@ uint8_t platformUpdate() { // Update input state. PLATFORM_RAYLIB.inputPrevious = PLATFORM_RAYLIB.inputCurrent; PLATFORM_RAYLIB.inputCurrent = 0; - rlkeyboardmap_t *map = RL_KEYBOARD_MAP; + const rlkeyboardmap_t *map = RL_KEYBOARD_MAP; do { if(IsKeyDown(map->raylibKey)) { PLATFORM_RAYLIB.inputCurrent |= map->action;