Brought over microjrpg cutscene system (partially implemented)

This commit is contained in:
2025-11-08 15:23:22 -06:00
parent bc4776f096
commit 0a83175b66
18 changed files with 391 additions and 3 deletions

View File

@@ -11,5 +11,6 @@ target_sources(${DUSK_TARGET_NAME}
) )
# Subdirs # Subdirs
add_subdirectory(cutscene)
add_subdirectory(entity) add_subdirectory(entity)
add_subdirectory(world) add_subdirectory(world)

View File

@@ -0,0 +1,14 @@
# Copyright (c) 2025 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
# Sources
target_sources(${DUSK_TARGET_NAME}
PRIVATE
cutscenesystem.c
cutscenemode.c
)
# Subdirs
add_subdirectory(item)

View File

@@ -0,0 +1,14 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "rpg/cutscene/item/cutsceneitem.h"
typedef struct cutscene_s {
const cutsceneitem_t *items;
uint8_t itemCount;
} cutscene_t;

View File

@@ -0,0 +1,19 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "rpg/cutscene/cutscenesystem.h"
bool_t cutsceneModeIsInputAllowed() {
switch(CUTSCENE_SYSTEM.mode) {
case CUTSCENE_MODE_FULL_FREEZE:
case CUTSCENE_MODE_INPUT_FREEZE:
return false;
default:
return true;
}
}

View File

@@ -0,0 +1,26 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "dusk.h"
typedef enum {
CUTSCENE_MODE_NONE,
CUTSCENE_MODE_FULL_FREEZE,
CUTSCENE_MODE_INPUT_FREEZE,
CUTSCENE_MODE_GAMEPLAY
} cutscenemode_t;
// Default mode for all cutscenes.
#define CUTSCENE_MODE_INITIAL CUTSCENE_MODE_INPUT_FREEZE
/**
* Check if input is allowed in the current cutscene mode.
*
* @return true if input is allowed, false otherwise.
*/
bool_t cutsceneModeIsInputAllowed();

View File

@@ -0,0 +1,56 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "cutscenesystem.h"
#include "util/memory.h"
cutscenesystem_t CUTSCENE_SYSTEM;
void cutsceneSystemInit() {
memoryZero(&CUTSCENE_SYSTEM, sizeof(cutscenesystem_t));
}
void cutsceneSystemStartCutscene(const cutscene_t *cutscene) {
CUTSCENE_SYSTEM.scene = cutscene;
CUTSCENE_SYSTEM.mode = CUTSCENE_MODE_INITIAL;
CUTSCENE_SYSTEM.currentItem = 0xFF;// Set to 0xFF so start wraps.
cutsceneSystemNext();
}
void cutsceneSystemUpdate() {
if(CUTSCENE_SYSTEM.scene == NULL) return;
const cutsceneitem_t *item = cutsceneSystemGetCurrentItem();
cutsceneItemUpdate(item, &CUTSCENE_SYSTEM.data);
}
void cutsceneSystemNext() {
if(CUTSCENE_SYSTEM.scene == NULL) return;
CUTSCENE_SYSTEM.currentItem++;
// End of the cutscene?
if(
CUTSCENE_SYSTEM.currentItem >= CUTSCENE_SYSTEM.scene->itemCount
) {
CUTSCENE_SYSTEM.scene = NULL;
CUTSCENE_SYSTEM.currentItem = 0xFF;
CUTSCENE_SYSTEM.mode = CUTSCENE_MODE_NONE;
return;
}
// Start item.
const cutsceneitem_t *item = cutsceneSystemGetCurrentItem();
memset(&CUTSCENE_SYSTEM.data, 0, sizeof(CUTSCENE_SYSTEM.data));
cutsceneItemStart(item, &CUTSCENE_SYSTEM.data);
}
const cutsceneitem_t * cutsceneSystemGetCurrentItem() {
if(CUTSCENE_SYSTEM.scene == NULL) return NULL;
return &CUTSCENE_SYSTEM.scene->items[CUTSCENE_SYSTEM.currentItem];
}

View File

@@ -0,0 +1,50 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "cutscene.h"
#include "cutscenemode.h"
typedef struct {
const cutscene_t *scene;
uint8_t currentItem;
// Data (used by the current item).
cutsceneitemdata_t data;
cutscenemode_t mode;
} cutscenesystem_t;
extern cutscenesystem_t CUTSCENE_SYSTEM;
/**
* Initialize the cutscene system.
*/
void cutsceneSystemInit();
/**
* Start a cutscene.
*
* @param cutscene Pointer to the cutscene to start.
*/
void cutsceneSystemStartCutscene(const cutscene_t *cutscene);
/**
* Advance to the next item in the cutscene.
*/
void cutsceneSystemNext();
/**
* Update the cutscene system for one frame.
*/
void cutsceneSystemUpdate();
/**
* Get the current cutscene item.
*
* @return Pointer to the current cutscene item.
*/
const cutsceneitem_t * cutsceneSystemGetCurrentItem();

View File

@@ -0,0 +1,10 @@
# Copyright (c) 2025 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
# Sources
target_sources(${DUSK_TARGET_NAME}
PRIVATE
cutsceneitem.c
)

View File

@@ -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 "dusk.h"
typedef void (*cutscenecallback_t)(void);

View File

@@ -0,0 +1,13 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "dusk.h"
typedef struct cutscene_s cutscene_t;
typedef cutscene_t* cutscenecutscene_t;

View File

@@ -0,0 +1,47 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "rpg/cutscene/cutscenesystem.h"
#include "input/input.h"
#include "time/time.h"
void cutsceneItemStart(const cutsceneitem_t *item, cutsceneitemdata_t *data) {
switch(item->type) {
case CUTSCENE_ITEM_TYPE_TEXT: {
strncpy(data->text.buffer, item->text, CUTSCENE_TEXT_BUFFER);
data->text.length = strlen(data->text.buffer);
break;
}
case CUTSCENE_ITEM_TYPE_WAIT:
data->wait = item->wait;
break;
case CUTSCENE_ITEM_TYPE_CALLBACK:
if(item->callback != NULL) item->callback();
break;
case CUTSCENE_ITEM_TYPE_CUTSCENE:
if(item->cutscene != NULL) cutsceneSystemStartCutscene(item->cutscene);
break;
default:
break;
}
}
void cutsceneItemUpdate(const cutsceneitem_t *item, cutsceneitemdata_t *data) {
switch(item->type) {
case CUTSCENE_ITEM_TYPE_WAIT:
data->wait -= TIME.fixedDelta;
if(data->wait <= 0) cutsceneSystemNext();
break;
default:
break;
}
}

View File

@@ -0,0 +1,53 @@
/**
* 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"
#include "cutscenecutscene.h"
typedef enum {
CUTSCENE_ITEM_TYPE_NULL,
CUTSCENE_ITEM_TYPE_TEXT,
CUTSCENE_ITEM_TYPE_CALLBACK,
CUTSCENE_ITEM_TYPE_WAIT,
CUTSCENE_ITEM_TYPE_CUTSCENE
} cutsceneitemtype_t;
typedef struct cutsceneitem_s {
cutsceneitemtype_t type;
// Arguments/Data that will be used when this item is invoked.
union {
cutscenetext_t text;
cutscenecallback_t callback;
cutscenewait_t wait;
cutscenecutscene_t cutscene;
};
} cutsceneitem_t;
typedef union {
cutscenetextdata_t text;
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 cutsceneItemUpdate(const cutsceneitem_t *item, cutsceneitemdata_t *data);

View File

@@ -0,0 +1,19 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "dusk.h"
#define CUTSCENE_TEXT_BUFFER 256
typedef const char_t *cutscenetext_t;
typedef struct cutscenetextdata_s {
char_t buffer[CUTSCENE_TEXT_BUFFER];
uint8_t length;
uint8_t scroll;
} cutscenetextdata_t;

View File

@@ -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 "dusk.h"
typedef float_t cutscenewait_t;
typedef float_t cutscenewaitdata_t;

View File

@@ -0,0 +1,30 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "rpg/cutscene/cutscenesystem.h"
static const cutsceneitem_t TEST_CUTSCENE_ONE_ITEMS[] = {
{ .type = CUTSCENE_ITEM_TYPE_TEXT, .text = "This is a test cutscene." },
{ .type = CUTSCENE_ITEM_TYPE_WAIT, .wait = 2.0f },
{ .type = CUTSCENE_ITEM_TYPE_TEXT, .text = "It has multiple lines of text.\nAnd waits in between." },
};
static const cutscene_t TEST_CUTSCENE_ONE = {
.items = TEST_CUTSCENE_ONE_ITEMS,
.itemCount = sizeof(TEST_CUTSCENE_ONE_ITEMS) / sizeof(cutsceneitem_t)
};
static const cutsceneitem_t TEST_CUTSCENE_TWO_ITEMS[] = {
{ .type = CUTSCENE_ITEM_TYPE_WAIT, .wait = 1.0f },
// { .type = CUTSCENE_ITEM_TYPE_CUTSCENE, .cutscene = &TEST_CUTSCENE_ONE },
};
static const cutscene_t TEST_CUTSCENE = {
.items = TEST_CUTSCENE_TWO_ITEMS,
.itemCount = sizeof(TEST_CUTSCENE_TWO_ITEMS) / sizeof(cutsceneitem_t)
};

View File

@@ -10,6 +10,7 @@
#include "util/memory.h" #include "util/memory.h"
#include "time/time.h" #include "time/time.h"
#include "util/math.h" #include "util/math.h"
#include "rpg/cutscene/cutscenemode.h"
entity_t ENTITIES[ENTITY_COUNT]; entity_t ENTITIES[ENTITY_COUNT];
@@ -43,7 +44,10 @@ void entityUpdate(entity_t *entity) {
} }
// Movement code. // Movement code.
if(ENTITY_CALLBACKS[entity->type].movement != NULL) { if(
cutsceneModeIsInputAllowed() &&
ENTITY_CALLBACKS[entity->type].movement != NULL
) {
ENTITY_CALLBACKS[entity->type].movement(entity); ENTITY_CALLBACKS[entity->type].movement(entity);
} }
} }

View File

@@ -8,6 +8,8 @@
#include "entity.h" #include "entity.h"
#include "assert/assert.h" #include "assert/assert.h"
#include "rpg/cutscene/scene/testcutscene.h"
void npcInit(entity_t *entity) { void npcInit(entity_t *entity) {
assertNotNull(entity, "Entity pointer cannot be NULL"); assertNotNull(entity, "Entity pointer cannot be NULL");
} }
@@ -20,7 +22,7 @@ bool_t npcInteract(entity_t *player, entity_t *npc) {
assertNotNull(player, "Player entity pointer cannot be NULL"); assertNotNull(player, "Player entity pointer cannot be NULL");
assertNotNull(npc, "NPC entity pointer cannot be NULL"); assertNotNull(npc, "NPC entity pointer cannot be NULL");
printf("npc interact\n"); cutsceneSystemStartCutscene(&TEST_CUTSCENE);
return false; return false;
}; };

View File

@@ -8,6 +8,7 @@
#include "rpg.h" #include "rpg.h"
#include "entity/entity.h" #include "entity/entity.h"
#include "rpg/world/world.h" #include "rpg/world/world.h"
#include "rpg/cutscene/cutscenesystem.h"
#include "time/time.h" #include "time/time.h"
#include "rpgcamera.h" #include "rpgcamera.h"
#include "util/memory.h" #include "util/memory.h"
@@ -15,6 +16,9 @@
errorret_t rpgInit(void) { errorret_t rpgInit(void) {
memoryZero(ENTITIES, sizeof(ENTITIES)); memoryZero(ENTITIES, sizeof(ENTITIES));
// Init cutscene subsystem
cutsceneSystemInit();
// Init the world. // Init the world.
worldInit(); worldInit();
@@ -31,7 +35,7 @@ errorret_t rpgInit(void) {
ent = &ENTITIES[1]; ent = &ENTITIES[1];
entityInit(ent, ENTITY_TYPE_NPC); entityInit(ent, ENTITY_TYPE_NPC);
ent->position.x = 6, ent->position.y = 6; ent->position.x = 6, ent->position.y = 4;
// All Good! // All Good!
errorOk(); errorOk();
@@ -51,6 +55,9 @@ void rpgUpdate(void) {
if(ent->type == ENTITY_TYPE_NULL) continue; if(ent->type == ENTITY_TYPE_NULL) continue;
entityUpdate(ent); entityUpdate(ent);
} while(++ent < &ENTITIES[ENTITY_COUNT]); } while(++ent < &ENTITIES[ENTITY_COUNT]);
// Tick the cutscene system.
cutsceneSystemUpdate();
} }
void rpgDispose(void) { void rpgDispose(void) {