Restored cutscene code

This commit is contained in:
2026-07-23 09:15:47 -05:00
parent 0852b8463b
commit 0667a44e14
55 changed files with 3066 additions and 24 deletions
+11
View File
@@ -0,0 +1,11 @@
# Copyright (c) 2026 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
target_sources(${DUSK_LIBRARY_TARGET_NAME}
PUBLIC
cutscenesystem.c
)
add_subdirectory(item)
+127
View File
@@ -0,0 +1,127 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "cutscene/cutscenepause.h"
#include "cutscene/item/cutsceneitem.h"
typedef struct cutscene_s {
const cutsceneitem_t *items;
uint8_t itemCount;
cutscenepause_t pause;
/** Bytes of CUTSCENE_SYSTEM.userData this cutscene's callbacks use. */
size_t dataSize;
} cutscene_t;
/**
* Declares a static cutscene_t named NAME with the given items.
*
* @param NAME Identifier for the resulting cutscene_t.
* @param SIZE Bytes of scratch user data this cutscene's callbacks use.
* @param PAUSE_TYPE A cutscenepause_t value applied while running.
* @param ... cutsceneitem_t initializers, see the CUTSCENE_* item macros.
*/
#define CUTSCENE(NAME, SIZE, PAUSE_TYPE, ...) \
static const cutsceneitem_t NAME##_ITEMS[] = { __VA_ARGS__ }; \
static const cutscene_t NAME = { \
NAME##_ITEMS, \
sizeof(NAME##_ITEMS) / sizeof(cutsceneitem_t), \
(PAUSE_TYPE), \
(SIZE) \
}
#define CUTSCENE_TEXT(TEXT) \
{ .type = CUTSCENE_ITEM_TYPE_TEXT, .text = { TEXT } }
#define CUTSCENE_CALLBACK(CALLBACK) \
{ .type = CUTSCENE_ITEM_TYPE_CALLBACK, .callback = (CALLBACK) }
#define CUTSCENE_WAIT(SECONDS) \
{ .type = CUTSCENE_ITEM_TYPE_WAIT, .wait = (SECONDS) }
#define CUTSCENE_CUTSCENE(CUTSCENE_PTR) \
{ .type = CUTSCENE_ITEM_TYPE_CUTSCENE, .cutscene = (CUTSCENE_PTR) }
#define CUTSCENE_SET_PAUSE(PAUSE) \
{ .type = CUTSCENE_ITEM_TYPE_SET_PAUSE, .setPause = (PAUSE) }
/**
* @param ITEMS Identifier of a previously-declared cutsceneitem_t array;
* its element count is taken via sizeof(ITEMS), so it must be a real
* array, not a pointer.
*/
#define CUTSCENE_CONCURRENT(ITEMS) \
{ \
.type = CUTSCENE_ITEM_TYPE_CONCURRENT, \
.concurrent = { (ITEMS), sizeof(ITEMS) / sizeof(cutsceneitem_t) } \
}
#define CUTSCENE_ENTITY_TELEPORT(ENTITY_INDEX, X, Y, Z) \
{ \
.type = CUTSCENE_ITEM_TYPE_ENTITY_TELEPORT, \
.entityTeleport = { (ENTITY_INDEX), { (X), (Y), (Z) } } \
}
#define CUTSCENE_ENTITY_WALK_TO(ENTITY_INDEX, X, Y, Z, SPEED) \
{ \
.type = CUTSCENE_ITEM_TYPE_ENTITY_WALK_TO, \
.entityWalkTo = { \
(ENTITY_INDEX), (const vec3[]){ { (X), (Y), (Z) } }, 1, (SPEED) \
} \
}
/**
* @param POSITIONS Identifier of a previously-declared vec3 array of
* waypoints; its element count is taken via sizeof(POSITIONS), so it
* must be a real array, not a pointer.
*/
#define CUTSCENE_ENTITY_WALK_PATH(ENTITY_INDEX, POSITIONS, SPEED) \
{ \
.type = CUTSCENE_ITEM_TYPE_ENTITY_WALK_TO, \
.entityWalkTo = { \
(ENTITY_INDEX), (POSITIONS), sizeof(POSITIONS) / sizeof(vec3), (SPEED) \
} \
}
#define CUTSCENE_ENTITY_WALK_TO_ENTITY( \
ENTITY_INDEX, TARGET_ENTITY_INDEX, OFFSET_X, OFFSET_Z, SPEED \
) \
{ \
.type = CUTSCENE_ITEM_TYPE_ENTITY_WALK_TO_ENTITY, \
.entityWalkToEntity = { \
(ENTITY_INDEX), (TARGET_ENTITY_INDEX), (OFFSET_X), (OFFSET_Z), (SPEED) \
} \
}
#define CUTSCENE_ENTITY_TURN(ENTITY_INDEX, YAW) \
{ \
.type = CUTSCENE_ITEM_TYPE_ENTITY_TURN, \
.entityTurn = { (ENTITY_INDEX), (YAW) } \
}
#define CUTSCENE_ENTITY_ADD(PREFAB_NAME, X, Y, Z) \
{ \
.type = CUTSCENE_ITEM_TYPE_ENTITY_ADD, \
.entityAdd = { (PREFAB_NAME), { (X), (Y), (Z) } } \
}
#define CUTSCENE_ENTITY_REMOVE(ENTITY_INDEX) \
{ \
.type = CUTSCENE_ITEM_TYPE_ENTITY_REMOVE, \
.entityRemove = { (ENTITY_INDEX) } \
}
/**
* @param MESSAGE Shown in UI_TEXTBOX_MAIN; "" uses
* ENTITY_INTERACTABLE_ITEM_PICKUP_MESSAGE_DEFAULT.
*/
#define CUTSCENE_ENTITY_ITEM_PICKUP(ENTITY_INDEX, MESSAGE) \
{ \
.type = CUTSCENE_ITEM_TYPE_ENTITY_ITEM_PICKUP, \
.entityItemPickup = { (ENTITY_INDEX), MESSAGE } \
}
+24
View File
@@ -0,0 +1,24 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "dusk.h"
typedef uint8_t cutscenepause_t;
#define CUTSCENE_PAUSE_NONE ((cutscenepause_t)0)
#define CUTSCENE_PAUSE_NPC ((cutscenepause_t)(1 << 0))
#define CUTSCENE_PAUSE_PLAYER ((cutscenepause_t)(1 << 1))
#define CUTSCENE_PAUSE_WORLD ((cutscenepause_t)(1 << 2))
#define CUTSCENE_PAUSE_DEFAULT ((cutscenepause_t)( \
CUTSCENE_PAUSE_NPC | CUTSCENE_PAUSE_PLAYER \
))
#define CUTSCENE_PAUSE_ALL ((cutscenepause_t)( \
CUTSCENE_PAUSE_NPC | CUTSCENE_PAUSE_PLAYER | CUTSCENE_PAUSE_WORLD \
))
+102
View File
@@ -0,0 +1,102 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "cutscene/cutscenesystem.h"
#include "scene/scene.h"
#include "util/memory.h"
#include "assert/assert.h"
cutscenesystem_t CUTSCENE_SYSTEM;
errorret_t cutsceneSystemInit(void) {
memoryZero(&CUTSCENE_SYSTEM, sizeof(cutscenesystem_t));
CUTSCENE_SYSTEM.entityInteract = ENTITY_ID_INVALID;
CUTSCENE_SYSTEM.entityInteracted = ENTITY_ID_INVALID;
CUTSCENE_SYSTEM.entityLastCreated = ENTITY_ID_INVALID;
CUTSCENE_SYSTEM.entityLastRef = ENTITY_ID_INVALID;
errorOk();
}
void cutsceneSystemStartCutscene(const cutscene_t *cutscene) {
cutsceneSystemStartCutsceneWith(
cutscene, ENTITY_ID_INVALID, ENTITY_ID_INVALID
);
}
void cutsceneSystemStartCutsceneWith(
const cutscene_t *cutscene,
const entityid_t interact,
const entityid_t interacted
) {
assertNotNull(cutscene, "cutscene must not be NULL");
assertTrue(
cutscene->dataSize <= CUTSCENE_SYSTEM_SIZE_MAX,
"Cutscene dataSize exceeds CUTSCENE_SYSTEM_SIZE_MAX"
);
CUTSCENE_SYSTEM.mgr = sceneGetEntities(sceneGetActive());
CUTSCENE_SYSTEM.scene = cutscene;
CUTSCENE_SYSTEM.currentItem = 0;
CUTSCENE_SYSTEM.pause = cutscene->pause;
CUTSCENE_SYSTEM.entityInteract = interact;
CUTSCENE_SYSTEM.entityInteracted = interacted;
CUTSCENE_SYSTEM.entityLastCreated = ENTITY_ID_INVALID;
CUTSCENE_SYSTEM.entityLastRef = ENTITY_ID_INVALID;
memoryZero(&CUTSCENE_SYSTEM.data, sizeof(cutsceneitemdata_t));
if(cutscene->dataSize > 0) {
memoryZero(CUTSCENE_SYSTEM.userData, cutscene->dataSize);
}
if(cutscene->itemCount > 0) {
cutsceneItemStart(&cutscene->items[0], &CUTSCENE_SYSTEM.data);
}
}
entityid_t cutsceneSystemGetEntity(const uint8_t entityIndex) {
switch(entityIndex) {
case CUTSCENE_ENTITY_INTERACT: return CUTSCENE_SYSTEM.entityInteract;
case CUTSCENE_ENTITY_INTERACTED: return CUTSCENE_SYSTEM.entityInteracted;
case CUTSCENE_ENTITY_LAST_CREATED:
return CUTSCENE_SYSTEM.entityLastCreated;
case CUTSCENE_ENTITY_LAST_REF: return CUTSCENE_SYSTEM.entityLastRef;
default: return (entityid_t)entityIndex;
}
}
void cutsceneSystemNext(void) {
CUTSCENE_SYSTEM.currentItem++;
memoryZero(&CUTSCENE_SYSTEM.data, sizeof(cutsceneitemdata_t));
if(CUTSCENE_SYSTEM.currentItem >= CUTSCENE_SYSTEM.scene->itemCount) {
CUTSCENE_SYSTEM.scene = NULL;
CUTSCENE_SYSTEM.pause = CUTSCENE_PAUSE_NONE;
return;
}
cutsceneItemStart(cutsceneSystemGetCurrentItem(), &CUTSCENE_SYSTEM.data);
}
errorret_t cutsceneSystemUpdate(void) {
if(CUTSCENE_SYSTEM.scene == NULL) errorOk();
if(cutsceneItemUpdate(
cutsceneSystemGetCurrentItem(), &CUTSCENE_SYSTEM.data
)) {
cutsceneSystemNext();
}
errorOk();
}
const cutsceneitem_t *cutsceneSystemGetCurrentItem(void) {
if(CUTSCENE_SYSTEM.scene == NULL) return NULL;
return &CUTSCENE_SYSTEM.scene->items[CUTSCENE_SYSTEM.currentItem];
}
errorret_t cutsceneSystemDispose(void) {
errorOk();
}
+149
View File
@@ -0,0 +1,149 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "entity/entitybase.h"
#include "cutscene/cutscene.h"
#include "error/error.h"
/** Resolves to CUTSCENE_SYSTEM.entityInteract; see
* cutsceneSystemGetEntity(). */
#define CUTSCENE_ENTITY_INTERACT ((entityid_t)0xFE)
/** Resolves to CUTSCENE_SYSTEM.entityInteracted; see
* cutsceneSystemGetEntity(). */
#define CUTSCENE_ENTITY_INTERACTED ((entityid_t)0xFD)
/** Resolves to CUTSCENE_SYSTEM.entityLastCreated; see
* cutsceneSystemGetEntity(). */
#define CUTSCENE_ENTITY_LAST_CREATED ((entityid_t)0xFC)
/** Resolves to CUTSCENE_SYSTEM.entityLastRef; see
* cutsceneSystemGetEntity(). */
#define CUTSCENE_ENTITY_LAST_REF ((entityid_t)0xFB)
/** Size in bytes of CUTSCENE_SYSTEM.userData. */
#define CUTSCENE_SYSTEM_SIZE_MAX 8192
typedef struct {
/** The entity manager the running cutscene's entity items operate on;
* resolved from the active scene when a cutscene starts. */
entitymanager_t *mgr;
/** The currently running cutscene, or NULL if none is running. */
const cutscene_t *scene;
/** Index of the currently running item within scene->items. */
uint8_t currentItem;
/** Pause flags applied by the running cutscene; see cutscenepause_t. */
cutscenepause_t pause;
/** Entity that initiated the current cutscene, if started via
* cutsceneSystemStartCutsceneWith(); see CUTSCENE_ENTITY_INTERACT. */
entityid_t entityInteract;
/** Entity that was interacted with to start the current cutscene, if
* started via cutsceneSystemStartCutsceneWith(); see
* CUTSCENE_ENTITY_INTERACTED. */
entityid_t entityInteracted;
/** Entity most recently spawned by a CUTSCENE_ENTITY_ADD item; see
* CUTSCENE_ENTITY_LAST_CREATED. */
entityid_t entityLastCreated;
/** Entity most recently referenced by CUTSCENE_ENTITY_LAST_CREATED/
* CUTSCENE_ENTITY_LAST_REF; see CUTSCENE_ENTITY_LAST_REF. */
entityid_t entityLastRef;
/** Runtime data for the currently running item. */
cutsceneitemdata_t data;
/** Scratch storage for a running cutscene's own state (see
* cutscene_t.dataSize) and for CUTSCENE_CALLBACK's user pointer. */
uint8_t userData[CUTSCENE_SYSTEM_SIZE_MAX];
} cutscenesystem_t;
extern cutscenesystem_t CUTSCENE_SYSTEM;
/**
* Initializes CUTSCENE_SYSTEM. No cutscene is running until
* cutsceneSystemStartCutscene()/cutsceneSystemStartCutsceneWith() is
* called.
*
* @return Error state.
*/
errorret_t cutsceneSystemInit(void);
/**
* Starts a cutscene. Equivalent to cutsceneSystemStartCutsceneWith() with
* both entity IDs set to ENTITY_ID_INVALID.
*
* @param cutscene The cutscene to start.
*/
void cutsceneSystemStartCutscene(const cutscene_t *cutscene);
/**
* Starts a cutscene, recording which entities (if any) initiated it via
* an interaction, so its items can reference them through
* CUTSCENE_ENTITY_INTERACT/CUTSCENE_ENTITY_INTERACTED. Resolves
* CUTSCENE_SYSTEM.mgr from the active scene (see sceneGetActive()).
*
* If a cutscene is already running, this replaces it outright -- there
* is no call/return stack, so starting a cutscene from within another
* (see CUTSCENE_CUTSCENE()) is a one-way jump; the outer cutscene's
* remaining items are abandoned, not resumed afterwards.
*
* @param cutscene The cutscene to start.
* @param interact The entity that initiated the interaction, or
* ENTITY_ID_INVALID.
* @param interacted The entity that was interacted with, or
* ENTITY_ID_INVALID.
*/
void cutsceneSystemStartCutsceneWith(
const cutscene_t *cutscene,
const entityid_t interact,
const entityid_t interacted
);
/**
* Resolves an item's entityIndex field into a real entity ID: the
* CUTSCENE_ENTITY_* sentinels resolve to their corresponding
* CUTSCENE_SYSTEM field, any other value passes through unchanged as a
* literal entity ID within CUTSCENE_SYSTEM.mgr.
*
* @param entityIndex The entityIndex field from a cutscene item.
* @return The resolved entity ID.
*/
entityid_t cutsceneSystemGetEntity(const uint8_t entityIndex);
/**
* Advances to the next item in the running cutscene (starting it), or
* ends the cutscene if none remain. Called by cutsceneSystemUpdate() once
* the current item completes.
*/
void cutsceneSystemNext(void);
/**
* Updates the running cutscene: ticks the current item, advancing to the
* next one (see cutsceneSystemNext()) once it completes. No-op if no
* cutscene is running.
*
* @return Error state.
*/
errorret_t cutsceneSystemUpdate(void);
/**
* Gets the currently running item.
*
* @return The current item, or NULL if no cutscene is running.
*/
const cutsceneitem_t *cutsceneSystemGetCurrentItem(void);
/**
* Disposes CUTSCENE_SYSTEM.
*
* @return Error state.
*/
errorret_t cutsceneSystemDispose(void);
+14
View File
@@ -0,0 +1,14 @@
# Copyright (c) 2026 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
target_sources(${DUSK_LIBRARY_TARGET_NAME}
PUBLIC
cutscenecallback.c
cutsceneitem.c
)
add_subdirectory(control)
add_subdirectory(entity)
add_subdirectory(ui)
@@ -0,0 +1,11 @@
# Copyright (c) 2026 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
target_sources(${DUSK_LIBRARY_TARGET_NAME}
PUBLIC
cutsceneconcurrent.c
cutscenesetpause.c
cutscenewait.c
)
@@ -0,0 +1,46 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "cutscene/item/cutsceneitem.h"
#include "assert/assert.h"
void cutsceneConcurrentStart(
const cutsceneitem_t *item,
cutsceneitemdata_t *data
) {
assertTrue(
item->concurrent.count <= CUTSCENE_CONCURRENT_MAX,
"Too many items in CUTSCENE_CONCURRENT"
);
for(uint8_t i = 0; i < item->concurrent.count; i++) {
assertTrue(
item->concurrent.items[i].type != CUTSCENE_ITEM_TYPE_CONCURRENT,
"Concurrent items cannot be nested"
);
cutsceneItemStart(
&item->concurrent.items[i],
(cutsceneitemdata_t *)&data->concurrent.childData[i]
);
}
}
bool_t cutsceneConcurrentUpdate(
const cutsceneitem_t *item,
cutsceneitemdata_t *data
) {
for(uint8_t i = 0; i < item->concurrent.count; i++) {
if(data->concurrent.doneMask & (1u << i)) continue;
if(cutsceneItemUpdate(
&item->concurrent.items[i],
(cutsceneitemdata_t *)&data->concurrent.childData[i]
)) {
data->concurrent.doneMask |= (uint8_t)(1u << i);
}
}
uint8_t allDone = (uint8_t)((1u << item->concurrent.count) - 1u);
return data->concurrent.doneMask == allDone;
}
@@ -0,0 +1,62 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "cutscenewait.h"
#include "cutscene/item/entity/cutsceneentitywalkto.h"
typedef struct cutsceneitem_s cutsceneitem_t;
typedef union cutsceneitemdata_u cutsceneitemdata_t;
/** Maximum number of items that may run inside a CUTSCENE_CONCURRENT. */
#define CUTSCENE_CONCURRENT_MAX 8
/**
* Static (const) data for a concurrent cutscene item.
*/
typedef struct {
const cutsceneitem_t *items;
uint8_t count;
} cutsceneconcurrent_t;
/**
* Runtime data for one non-concurrent child item.
* Concurrent items cannot be nested.
*/
typedef union {
cutscenewaitdata_t wait;
cutsceneentitywalktodata_t entityWalkTo;
} cutsceneconcurrentchilddata_t;
/** Runtime data for a running concurrent item. */
typedef struct {
cutsceneconcurrentchilddata_t childData[CUTSCENE_CONCURRENT_MAX];
uint8_t doneMask;
} cutsceneconcurrentdata_t;
/**
* Starts a concurrent item (starts all child items simultaneously).
*
* @param item The cutscene item.
* @param data Runtime data storage.
*/
void cutsceneConcurrentStart(
const cutsceneitem_t *item,
cutsceneitemdata_t *data
);
/**
* Updates a concurrent item (ticks all unfinished children).
*
* @param item The cutscene item.
* @param data Runtime data storage.
* @returns true once every child has completed.
*/
bool_t cutsceneConcurrentUpdate(
const cutsceneitem_t *item,
cutsceneitemdata_t *data
);
@@ -0,0 +1,23 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "cutscene/item/cutsceneitem.h"
#include "cutscene/cutscenesystem.h"
void cutsceneSetPauseStart(
const cutsceneitem_t *item,
cutsceneitemdata_t *data
) {
CUTSCENE_SYSTEM.pause = item->setPause;
}
bool_t cutsceneSetPauseUpdate(
const cutsceneitem_t *item,
cutsceneitemdata_t *data
) {
return true;
}
@@ -0,0 +1,35 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "cutscene/cutscenepause.h"
typedef struct cutsceneitem_s cutsceneitem_t;
typedef union cutsceneitemdata_u cutsceneitemdata_t;
/**
* Starts a set-pause item (applies the new pause flags immediately).
*
* @param item The cutscene item.
* @param data Runtime data storage.
*/
void cutsceneSetPauseStart(
const cutsceneitem_t *item,
cutsceneitemdata_t *data
);
/**
* Updates a set-pause item (always completes immediately).
*
* @param item The cutscene item.
* @param data Runtime data storage.
* @returns true always.
*/
bool_t cutsceneSetPauseUpdate(
const cutsceneitem_t *item,
cutsceneitemdata_t *data
);
@@ -0,0 +1,24 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "cutscene/item/cutsceneitem.h"
#include "time/time.h"
void cutsceneWaitStart(
const cutsceneitem_t *item,
cutsceneitemdata_t *data
) {
data->wait = item->wait;
}
bool_t cutsceneWaitUpdate(
const cutsceneitem_t *item,
cutsceneitemdata_t *data
) {
data->wait -= TIME.delta;
return data->wait <= 0;
}
@@ -0,0 +1,38 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "dusk.h"
typedef struct cutsceneitem_s cutsceneitem_t;
typedef union cutsceneitemdata_u cutsceneitemdata_t;
typedef float_t cutscenewait_t;
typedef float_t cutscenewaitdata_t;
/**
* Starts a wait item (stores the duration in data).
*
* @param item The cutscene item.
* @param data Runtime data storage.
*/
void cutsceneWaitStart(
const cutsceneitem_t *item,
cutsceneitemdata_t *data
);
/**
* Updates a wait item.
*
* @param item The cutscene item.
* @param data Runtime data storage.
* @returns true when the wait has elapsed.
*/
bool_t cutsceneWaitUpdate(
const cutsceneitem_t *item,
cutsceneitemdata_t *data
);
@@ -0,0 +1,23 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "cutsceneitem.h"
#include "cutscene/cutscenesystem.h"
void cutsceneCallbackStart(
const cutsceneitem_t *item,
cutsceneitemdata_t *data
) {
if(item->callback != NULL) item->callback(CUTSCENE_SYSTEM.userData);
}
bool_t cutsceneCallbackUpdate(
const cutsceneitem_t *item,
cutsceneitemdata_t *data
) {
return true;
}
@@ -0,0 +1,38 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "dusk.h"
typedef struct cutsceneitem_s cutsceneitem_t;
typedef union cutsceneitemdata_u cutsceneitemdata_t;
/** @param user The cutscene's own userData scratch buffer; see cutscene_t. */
typedef void (*cutscenecallback_t)(void *user);
/**
* Starts a callback item (invokes the callback immediately).
*
* @param item The cutscene item.
* @param data Runtime data storage.
*/
void cutsceneCallbackStart(
const cutsceneitem_t *item,
cutsceneitemdata_t *data
);
/**
* Updates a callback item (always completes immediately).
*
* @param item The cutscene item.
* @param data Runtime data storage.
* @returns true always.
*/
bool_t cutsceneCallbackUpdate(
const cutsceneitem_t *item,
cutsceneitemdata_t *data
);
+88
View File
@@ -0,0 +1,88 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "cutscene/item/cutsceneitem.h"
#include "cutscene/cutscenesystem.h"
#include "assert/assert.h"
const cutsceneitemcallbacks_t
CUTSCENE_ITEM_CALLBACKS[CUTSCENE_ITEM_TYPE_COUNT] = {
[CUTSCENE_ITEM_TYPE_NULL] = { NULL, NULL },
[CUTSCENE_ITEM_TYPE_TEXT] = {
cutsceneTextStart, cutsceneTextUpdate
},
[CUTSCENE_ITEM_TYPE_CALLBACK] = {
cutsceneCallbackStart, cutsceneCallbackUpdate
},
[CUTSCENE_ITEM_TYPE_WAIT] = {
cutsceneWaitStart, cutsceneWaitUpdate
},
[CUTSCENE_ITEM_TYPE_CUTSCENE] = {
cutsceneCutsceneStart, cutsceneCutsceneUpdate
},
[CUTSCENE_ITEM_TYPE_SET_PAUSE] = {
cutsceneSetPauseStart, cutsceneSetPauseUpdate
},
[CUTSCENE_ITEM_TYPE_CONCURRENT] = {
cutsceneConcurrentStart, cutsceneConcurrentUpdate
},
[CUTSCENE_ITEM_TYPE_ENTITY_TELEPORT] = {
cutsceneEntityTeleportStart, cutsceneEntityTeleportUpdate
},
[CUTSCENE_ITEM_TYPE_ENTITY_WALK_TO] = {
cutsceneEntityWalkToStart, cutsceneEntityWalkToUpdate
},
[CUTSCENE_ITEM_TYPE_ENTITY_WALK_TO_ENTITY] = {
cutsceneEntityWalkToEntityStart, cutsceneEntityWalkToEntityUpdate
},
[CUTSCENE_ITEM_TYPE_ENTITY_TURN] = {
cutsceneEntityTurnStart, cutsceneEntityTurnUpdate
},
[CUTSCENE_ITEM_TYPE_ENTITY_ADD] = {
cutsceneEntityAddStart, cutsceneEntityAddUpdate
},
[CUTSCENE_ITEM_TYPE_ENTITY_REMOVE] = {
cutsceneEntityRemoveStart, cutsceneEntityRemoveUpdate
},
[CUTSCENE_ITEM_TYPE_ENTITY_ITEM_PICKUP] = {
cutsceneEntityItemPickupStart, cutsceneEntityItemPickupUpdate
}
};
void cutsceneItemStart(
const cutsceneitem_t *item,
cutsceneitemdata_t *data
) {
assertTrue(item->type < CUTSCENE_ITEM_TYPE_COUNT, "Invalid cutscene item");
cutsceneitemstartcallback_t start = CUTSCENE_ITEM_CALLBACKS[item->type].start;
if(start != NULL) start(item, data);
}
bool_t cutsceneItemUpdate(
const cutsceneitem_t *item,
cutsceneitemdata_t *data
) {
assertTrue(item->type < CUTSCENE_ITEM_TYPE_COUNT, "Invalid cutscene item");
cutsceneitemupdatecallback_t update =
CUTSCENE_ITEM_CALLBACKS[item->type].update;
if(update == NULL) return true;
return update(item, data);
}
void cutsceneCutsceneStart(
const cutsceneitem_t *item,
cutsceneitemdata_t *data
) {
cutsceneSystemStartCutscene(item->cutscene);
}
bool_t cutsceneCutsceneUpdate(
const cutsceneitem_t *item,
cutsceneitemdata_t *data
) {
return true;
}
+134
View File
@@ -0,0 +1,134 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "dusk.h"
#include "cutscene/item/cutscenecallback.h"
#include "cutscene/item/control/cutscenewait.h"
#include "cutscene/item/control/cutscenesetpause.h"
#include "cutscene/item/control/cutsceneconcurrent.h"
#include "cutscene/item/entity/cutsceneentityteleport.h"
#include "cutscene/item/entity/cutsceneentitywalkto.h"
#include "cutscene/item/entity/cutsceneentitywalktoentity.h"
#include "cutscene/item/entity/cutsceneentityturn.h"
#include "cutscene/item/entity/cutsceneentityadd.h"
#include "cutscene/item/entity/cutsceneentityremove.h"
#include "cutscene/item/entity/cutsceneentityitempickup.h"
#include "cutscene/item/ui/cutscenetext.h"
typedef struct cutscene_s cutscene_t;
typedef enum {
CUTSCENE_ITEM_TYPE_NULL,
CUTSCENE_ITEM_TYPE_TEXT,
CUTSCENE_ITEM_TYPE_CALLBACK,
CUTSCENE_ITEM_TYPE_WAIT,
CUTSCENE_ITEM_TYPE_CUTSCENE,
CUTSCENE_ITEM_TYPE_SET_PAUSE,
CUTSCENE_ITEM_TYPE_CONCURRENT,
CUTSCENE_ITEM_TYPE_ENTITY_TELEPORT,
CUTSCENE_ITEM_TYPE_ENTITY_WALK_TO,
CUTSCENE_ITEM_TYPE_ENTITY_WALK_TO_ENTITY,
CUTSCENE_ITEM_TYPE_ENTITY_TURN,
CUTSCENE_ITEM_TYPE_ENTITY_ADD,
CUTSCENE_ITEM_TYPE_ENTITY_REMOVE,
CUTSCENE_ITEM_TYPE_ENTITY_ITEM_PICKUP,
CUTSCENE_ITEM_TYPE_COUNT
} cutsceneitemtype_t;
typedef struct cutsceneitem_s {
cutsceneitemtype_t type;
union {
cutscenetext_t text;
cutscenecallback_t callback;
cutscenewait_t wait;
const cutscene_t *cutscene;
cutscenepause_t setPause;
cutsceneconcurrent_t concurrent;
cutsceneentityteleport_t entityTeleport;
cutsceneentitywalkto_t entityWalkTo;
cutsceneentitywalktoentity_t entityWalkToEntity;
cutsceneentityturn_t entityTurn;
cutsceneentityadd_t entityAdd;
cutsceneentityremove_t entityRemove;
cutsceneentityitempickup_t entityItemPickup;
};
} cutsceneitem_t;
typedef union cutsceneitemdata_u {
cutscenewaitdata_t wait;
cutsceneentitywalktodata_t entityWalkTo;
cutsceneconcurrentdata_t concurrent;
} cutsceneitemdata_t;
typedef void (*cutsceneitemstartcallback_t)(
const cutsceneitem_t *item,
cutsceneitemdata_t *data
);
typedef bool_t (*cutsceneitemupdatecallback_t)(
const cutsceneitem_t *item,
cutsceneitemdata_t *data
);
typedef struct {
cutsceneitemstartcallback_t start;
cutsceneitemupdatecallback_t update;
} cutsceneitemcallbacks_t;
extern const cutsceneitemcallbacks_t
CUTSCENE_ITEM_CALLBACKS[CUTSCENE_ITEM_TYPE_COUNT];
/**
* Starts a cutscene item by dispatching to its type's start callback.
*
* @param item The cutscene item.
* @param data Runtime data storage for the item.
*/
void cutsceneItemStart(
const cutsceneitem_t *item,
cutsceneitemdata_t *data
);
/**
* Updates a cutscene item by dispatching to its type's update callback.
*
* @param item The cutscene item.
* @param data Runtime data storage for the item.
* @returns true once the item has completed.
*/
bool_t cutsceneItemUpdate(
const cutsceneitem_t *item,
cutsceneitemdata_t *data
);
/**
* Starts a nested-cutscene item -- hands control of CUTSCENE_SYSTEM over to
* item->cutscene immediately (see cutsceneSystemStartCutscene()). This is a
* one-way jump, not a call/return: the outer cutscene's remaining items are
* abandoned, matching CUTSCENE_SYSTEM's single active-scene design.
*
* @param item The cutscene item.
* @param data Runtime data storage (unused).
*/
void cutsceneCutsceneStart(
const cutsceneitem_t *item,
cutsceneitemdata_t *data
);
/**
* Updates a nested-cutscene item (always completes immediately -- control
* has already moved to the nested scene by the time this would run).
*
* @param item The cutscene item.
* @param data Runtime data storage (unused).
* @returns true always.
*/
bool_t cutsceneCutsceneUpdate(
const cutsceneitem_t *item,
cutsceneitemdata_t *data
);
@@ -0,0 +1,15 @@
# Copyright (c) 2026 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
target_sources(${DUSK_LIBRARY_TARGET_NAME}
PUBLIC
cutsceneentityadd.c
cutsceneentityitempickup.c
cutsceneentityremove.c
cutsceneentityteleport.c
cutsceneentityturn.c
cutsceneentitywalkto.c
cutsceneentitywalktoentity.c
)
@@ -0,0 +1,48 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "cutscene/item/cutsceneitem.h"
#include "cutscene/cutscenesystem.h"
#include "entity/entitymanager.h"
#include "entity/entityprefab.h"
#include "entity/component/display/entityposition.h"
void cutsceneEntityAddStart(
const cutsceneitem_t *item,
cutsceneitemdata_t *data
) {
entityid_t entityId = entityManagerAdd(CUTSCENE_SYSTEM.mgr);
errorret_t ret = entityPrefabResolveAndApply(
CUTSCENE_SYSTEM.mgr, entityId, item->entityAdd.prefabName
);
if(errorIsNotOk(ret)) errorCatch(ret);
componentid_t posComp = entityGetComponent(
CUTSCENE_SYSTEM.mgr, entityId, COMPONENT_TYPE_POSITION
);
if(posComp != COMPONENT_ID_INVALID) {
vec3 position = {
item->entityAdd.position[0],
item->entityAdd.position[1],
item->entityAdd.position[2]
};
entityPositionSetLocalPosition(
CUTSCENE_SYSTEM.mgr, entityId, posComp, position
);
}
CUTSCENE_SYSTEM.entityLastCreated = entityId;
CUTSCENE_SYSTEM.entityLastRef = entityId;
}
bool_t cutsceneEntityAddUpdate(
const cutsceneitem_t *item,
cutsceneitemdata_t *data
) {
return true;
}
@@ -0,0 +1,46 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "dusk.h"
typedef struct cutsceneitem_s cutsceneitem_t;
typedef union cutsceneitemdata_u cutsceneitemdata_t;
typedef struct {
/** Name of the entity prefab to apply; see entityPrefabResolveAndApply(). */
const char_t *prefabName;
vec3 position;
} cutsceneentityadd_t;
/**
* Starts an entity add item: spawns a new entity, applies prefabName to
* it (see entityPrefabResolveAndApply()), and positions it if it ends up
* with a POSITION component. Sets CUTSCENE_SYSTEM.entityLastCreated (and
* entityLastRef) to the new entity. If prefabName fails to resolve, the
* error is logged (see errorCatch()) and the entity is left as-is --
* still created, just without whatever the prefab would have added.
*
* @param item The cutscene item.
* @param data Runtime data storage.
*/
void cutsceneEntityAddStart(
const cutsceneitem_t *item,
cutsceneitemdata_t *data
);
/**
* Updates an entity add item (always completes immediately).
*
* @param item The cutscene item.
* @param data Runtime data storage.
* @returns true always.
*/
bool_t cutsceneEntityAddUpdate(
const cutsceneitem_t *item,
cutsceneitemdata_t *data
);
@@ -0,0 +1,33 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "cutscene/item/cutsceneitem.h"
#include "cutscene/cutscenesystem.h"
#include "entity/entitymanager.h"
#include "entity/component/overworld/entityinteractable.h"
#include "ui/textbox/uitextboxmain.h"
void cutsceneEntityItemPickupStart(
const cutsceneitem_t *item,
cutsceneitemdata_t *data
) {
entityid_t entityId = cutsceneSystemGetEntity(
item->entityItemPickup.entityIndex
);
const char_t *message = item->entityItemPickup.message[0] != '\0'
? item->entityItemPickup.message
: ENTITY_INTERACTABLE_ITEM_PICKUP_MESSAGE_DEFAULT;
uiTextboxMainSetText(message);
entityDisposeDeep(CUTSCENE_SYSTEM.mgr, entityId);
}
bool_t cutsceneEntityItemPickupUpdate(
const cutsceneitem_t *item,
cutsceneitemdata_t *data
) {
return !uiTextboxMainIsActive();
}
@@ -0,0 +1,50 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "dusk.h"
typedef struct cutsceneitem_s cutsceneitem_t;
typedef union cutsceneitemdata_u cutsceneitemdata_t;
#define CUTSCENE_ENTITY_ITEM_PICKUP_MESSAGE_MAX 128
typedef struct {
uint8_t entityIndex;
/** Shown in UI_TEXTBOX_MAIN; empty means use
* ENTITY_INTERACTABLE_ITEM_PICKUP_MESSAGE_DEFAULT. */
char_t message[CUTSCENE_ENTITY_ITEM_PICKUP_MESSAGE_MAX];
} cutsceneentityitempickup_t;
/**
* Starts an entity item-pickup item: shows message (or the default
* pickup message if empty) in UI_TEXTBOX_MAIN and removes the entity
* immediately (see entityDisposeDeep()), mirroring
* ENTITY_INTERACTABLE_TYPE_ITEM_PICKUP's own interaction behavior for
* use within an authored cutscene.
*
* @param item The cutscene item.
* @param data Runtime data storage.
*/
void cutsceneEntityItemPickupStart(
const cutsceneitem_t *item,
cutsceneitemdata_t *data
);
/**
* Updates an entity item-pickup item -- waits until UI_TEXTBOX_MAIN is
* dismissed.
*
* @param item The cutscene item.
* @param data Runtime data storage.
* @returns true once the textbox is no longer active.
*/
bool_t cutsceneEntityItemPickupUpdate(
const cutsceneitem_t *item,
cutsceneitemdata_t *data
);
@@ -0,0 +1,27 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "cutscene/item/cutsceneitem.h"
#include "cutscene/cutscenesystem.h"
#include "entity/entitymanager.h"
void cutsceneEntityRemoveStart(
const cutsceneitem_t *item,
cutsceneitemdata_t *data
) {
entityid_t entityId = cutsceneSystemGetEntity(
item->entityRemove.entityIndex
);
entityDisposeDeep(CUTSCENE_SYSTEM.mgr, entityId);
}
bool_t cutsceneEntityRemoveUpdate(
const cutsceneitem_t *item,
cutsceneitemdata_t *data
) {
return true;
}
@@ -0,0 +1,40 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "dusk.h"
typedef struct cutsceneitem_s cutsceneitem_t;
typedef union cutsceneitemdata_u cutsceneitemdata_t;
typedef struct {
uint8_t entityIndex;
} cutsceneentityremove_t;
/**
* Starts an entity remove item (removes the entity from the world
* immediately, via entityDisposeDeep()).
*
* @param item The cutscene item.
* @param data Runtime data storage.
*/
void cutsceneEntityRemoveStart(
const cutsceneitem_t *item,
cutsceneitemdata_t *data
);
/**
* Updates an entity remove item (always completes immediately).
*
* @param item The cutscene item.
* @param data Runtime data storage.
* @returns true always.
*/
bool_t cutsceneEntityRemoveUpdate(
const cutsceneitem_t *item,
cutsceneitemdata_t *data
);
@@ -0,0 +1,40 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "cutscene/item/cutsceneitem.h"
#include "cutscene/cutscenesystem.h"
#include "entity/entitymanager.h"
#include "entity/component/display/entityposition.h"
void cutsceneEntityTeleportStart(
const cutsceneitem_t *item,
cutsceneitemdata_t *data
) {
entityid_t entityId = cutsceneSystemGetEntity(
item->entityTeleport.entityIndex
);
componentid_t posComp = entityGetComponent(
CUTSCENE_SYSTEM.mgr, entityId, COMPONENT_TYPE_POSITION
);
if(posComp == COMPONENT_ID_INVALID) return;
vec3 target = {
item->entityTeleport.target[0],
item->entityTeleport.target[1],
item->entityTeleport.target[2]
};
entityPositionSetLocalPosition(
CUTSCENE_SYSTEM.mgr, entityId, posComp, target
);
}
bool_t cutsceneEntityTeleportUpdate(
const cutsceneitem_t *item,
cutsceneitemdata_t *data
) {
return true;
}
@@ -0,0 +1,42 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "dusk.h"
typedef struct cutsceneitem_s cutsceneitem_t;
typedef union cutsceneitemdata_u cutsceneitemdata_t;
typedef struct {
uint8_t entityIndex;
vec3 target;
} cutsceneentityteleport_t;
/**
* Starts an entity teleport item (teleports the entity immediately, via
* entityPositionSetLocalPosition()). No-op if the entity has no POSITION
* component.
*
* @param item The cutscene item.
* @param data Runtime data storage.
*/
void cutsceneEntityTeleportStart(
const cutsceneitem_t *item,
cutsceneitemdata_t *data
);
/**
* Updates an entity teleport item (always completes immediately).
*
* @param item The cutscene item.
* @param data Runtime data storage.
* @returns true always.
*/
bool_t cutsceneEntityTeleportUpdate(
const cutsceneitem_t *item,
cutsceneitemdata_t *data
);
@@ -0,0 +1,38 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "cutscene/item/cutsceneitem.h"
#include "cutscene/cutscenesystem.h"
#include "entity/entitymanager.h"
#include "entity/component/display/entityposition.h"
void cutsceneEntityTurnStart(
const cutsceneitem_t *item,
cutsceneitemdata_t *data
) {
entityid_t entityId = cutsceneSystemGetEntity(item->entityTurn.entityIndex);
componentid_t posComp = entityGetComponent(
CUTSCENE_SYSTEM.mgr, entityId, COMPONENT_TYPE_POSITION
);
if(posComp == COMPONENT_ID_INVALID) return;
vec3 rotation;
entityPositionGetLocalRotation(
CUTSCENE_SYSTEM.mgr, entityId, posComp, rotation
);
rotation[1] = item->entityTurn.yaw;
entityPositionSetLocalRotation(
CUTSCENE_SYSTEM.mgr, entityId, posComp, rotation
);
}
bool_t cutsceneEntityTurnUpdate(
const cutsceneitem_t *item,
cutsceneitemdata_t *data
) {
return true;
}
@@ -0,0 +1,45 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "dusk.h"
typedef struct cutsceneitem_s cutsceneitem_t;
typedef union cutsceneitemdata_u cutsceneitemdata_t;
typedef struct {
uint8_t entityIndex;
/** Target yaw, in radians. See entityPositionSetLocalRotation(). */
float_t yaw;
} cutsceneentityturn_t;
/**
* Starts an entity turn item: sets the entity's local yaw immediately.
* No-op if the entity has no POSITION component. Unlike the original
* tile-based version, there's no per-entity action/animation state to
* wait on here, so this snaps instantly rather than deferring to Update.
*
* @param item The cutscene item.
* @param data Runtime data storage.
*/
void cutsceneEntityTurnStart(
const cutsceneitem_t *item,
cutsceneitemdata_t *data
);
/**
* Updates an entity turn item (always completes immediately).
*
* @param item The cutscene item.
* @param data Runtime data storage.
* @returns true always.
*/
bool_t cutsceneEntityTurnUpdate(
const cutsceneitem_t *item,
cutsceneitemdata_t *data
);
@@ -0,0 +1,94 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "cutscene/item/cutsceneitem.h"
#include "cutscene/cutscenesystem.h"
#include "entity/entitymanager.h"
#include "entity/component/display/entityposition.h"
#include "time/time.h"
#include "util/math.h"
void cutsceneEntityWalkToStart(
const cutsceneitem_t *item,
cutsceneitemdata_t *data
) {
data->entityWalkTo.currentIndex = 0;
}
bool_t cutsceneEntityWalkToUpdate(
const cutsceneitem_t *item,
cutsceneitemdata_t *data
) {
uint8_t i = data->entityWalkTo.currentIndex;
entityid_t entityId = cutsceneSystemGetEntity(
item->entityWalkTo.entityIndex
);
float_t speed = item->entityWalkTo.speed > 0.0f
? item->entityWalkTo.speed : CUTSCENE_ENTITY_WALK_SPEED_DEFAULT;
vec3 target = {
item->entityWalkTo.positions[i][0],
item->entityWalkTo.positions[i][1],
item->entityWalkTo.positions[i][2]
};
if(!cutsceneEntityStepToward(CUTSCENE_SYSTEM.mgr, entityId, target, speed))
return false;
i++;
if(i < item->entityWalkTo.count) {
data->entityWalkTo.currentIndex = i;
return false;
}
return true;
}
bool_t cutsceneEntityStepToward(
entitymanager_t *mgr,
const entityid_t entityId,
vec3 target,
const float_t speed
) {
componentid_t posComp = entityGetComponent(
mgr, entityId, COMPONENT_TYPE_POSITION
);
if(posComp == COMPONENT_ID_INVALID) return true;
vec3 pos;
entityPositionGetLocalPosition(mgr, entityId, posComp, pos);
vec3 delta = {
target[0] - pos[0], target[1] - pos[1], target[2] - pos[2]
};
float_t distSq = delta[0] * delta[0] + delta[1] * delta[1] +
delta[2] * delta[2];
if(distSq <= CUTSCENE_ENTITY_WALK_ARRIVE_THRESHOLD_SQ) {
entityPositionSetLocalPosition(mgr, entityId, posComp, target);
return true;
}
float_t dist = sqrtf(distSq);
float_t step = speed * TIME.delta;
float_t t = step >= dist ? 1.0f : step / dist;
vec3 newPos = {
pos[0] + delta[0] * t,
pos[1] + delta[1] * t,
pos[2] + delta[2] * t
};
entityPositionSetLocalPosition(mgr, entityId, posComp, newPos);
// Face the direction of travel: entityPlayerUpdate's convention is
// front = +local Z, so yaw = atan2(dx, dz) on the XZ ground plane.
if(mathAbs(delta[0]) > 0.0001f || mathAbs(delta[2]) > 0.0001f) {
vec3 rotation;
entityPositionGetLocalRotation(mgr, entityId, posComp, rotation);
rotation[1] = atan2f(delta[0], delta[2]);
entityPositionSetLocalRotation(mgr, entityId, posComp, rotation);
}
return false;
}
@@ -0,0 +1,73 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "entity/entitybase.h"
typedef struct cutsceneitem_s cutsceneitem_t;
typedef union cutsceneitemdata_u cutsceneitemdata_t;
/** Default speed for CUTSCENE_ENTITY_WALK_TO/_PATH, in units/second. */
#define CUTSCENE_ENTITY_WALK_SPEED_DEFAULT 4.0f
/** Below this squared distance, an entity is considered to have arrived. */
#define CUTSCENE_ENTITY_WALK_ARRIVE_THRESHOLD_SQ 0.0001f
typedef struct {
uint8_t entityIndex;
const vec3 *positions;
uint8_t count;
float_t speed;
} cutsceneentitywalkto_t;
typedef struct {
uint8_t currentIndex;
} cutsceneentitywalktodata_t;
/**
* Starts an entity walk-to item (resets the waypoint index).
*
* @param item The cutscene item.
* @param data Runtime data storage.
*/
void cutsceneEntityWalkToStart(
const cutsceneitem_t *item,
cutsceneitemdata_t *data
);
/**
* Updates an entity walk-to item (steps the entity toward the next
* waypoint).
*
* @param item The cutscene item.
* @param data Runtime data storage.
* @returns true once all waypoints have been reached.
*/
bool_t cutsceneEntityWalkToUpdate(
const cutsceneitem_t *item,
cutsceneitemdata_t *data
);
/**
* Steps an entity's local position directly toward target at speed
* units/second (straight-line, no pathfinding/obstacle avoidance), and
* faces it in the direction of travel. No-op (returns true immediately)
* if the entity has no POSITION component.
*
* @param mgr The entity manager that owns the entity.
* @param entityId The entity to move.
* @param target The local-space destination.
* @param speed Movement speed, in units/second.
* @returns true once the entity is within
* CUTSCENE_ENTITY_WALK_ARRIVE_THRESHOLD_SQ of target.
*/
bool_t cutsceneEntityStepToward(
entitymanager_t *mgr,
const entityid_t entityId,
vec3 target,
const float_t speed
);
@@ -0,0 +1,51 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "cutscene/item/cutsceneitem.h"
#include "cutscene/cutscenesystem.h"
#include "cutscene/item/entity/cutsceneentitywalkto.h"
#include "entity/entitymanager.h"
#include "entity/component/display/entityposition.h"
void cutsceneEntityWalkToEntityStart(
const cutsceneitem_t *item,
cutsceneitemdata_t *data
) {
}
bool_t cutsceneEntityWalkToEntityUpdate(
const cutsceneitem_t *item,
cutsceneitemdata_t *data
) {
entityid_t entityId = cutsceneSystemGetEntity(
item->entityWalkToEntity.entityIndex
);
entityid_t targetId = cutsceneSystemGetEntity(
item->entityWalkToEntity.targetEntityIndex
);
componentid_t targetPosComp = entityGetComponent(
CUTSCENE_SYSTEM.mgr, targetId, COMPONENT_TYPE_POSITION
);
if(targetPosComp == COMPONENT_ID_INVALID) return true;
vec3 targetPos;
entityPositionGetWorldPosition(
CUTSCENE_SYSTEM.mgr, targetId, targetPosComp, targetPos
);
vec3 dest = {
targetPos[0] + item->entityWalkToEntity.offsetX,
targetPos[1],
targetPos[2] + item->entityWalkToEntity.offsetZ
};
float_t speed = item->entityWalkToEntity.speed > 0.0f
? item->entityWalkToEntity.speed : CUTSCENE_ENTITY_WALK_SPEED_DEFAULT;
return cutsceneEntityStepToward(CUTSCENE_SYSTEM.mgr, entityId, dest, speed);
}
@@ -0,0 +1,52 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "dusk.h"
typedef struct cutsceneitem_s cutsceneitem_t;
typedef union cutsceneitemdata_u cutsceneitemdata_t;
typedef struct {
uint8_t entityIndex;
uint8_t targetEntityIndex;
/** Offset on the XZ ground plane from the target's current position. */
float_t offsetX;
float_t offsetZ;
float_t speed;
} cutsceneentitywalktoentity_t;
/**
* Starts an entity walk-to-entity item. No setup is needed -- the
* destination is recomputed from the target's live position every
* Update.
*
* @param item The cutscene item.
* @param data Runtime data storage.
*/
void cutsceneEntityWalkToEntityStart(
const cutsceneitem_t *item,
cutsceneitemdata_t *data
);
/**
* Updates an entity walk-to-entity item: re-reads the target entity's
* current world position each frame, applies the XZ offset, and steps
* the entity toward it (see cutsceneEntityStepToward()). Unlike the
* original tile-based version there's no terrain to resolve a Y from --
* the destination Y is taken directly from the target's own position.
*
* @param item The cutscene item.
* @param data Runtime data storage.
* @returns true once the entity has reached the target's side.
*/
bool_t cutsceneEntityWalkToEntityUpdate(
const cutsceneitem_t *item,
cutsceneitemdata_t *data
);
@@ -0,0 +1,9 @@
# Copyright (c) 2026 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
target_sources(${DUSK_LIBRARY_TARGET_NAME}
PUBLIC
cutscenetext.c
)
@@ -0,0 +1,23 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "cutscene/item/cutsceneitem.h"
#include "ui/textbox/uitextboxmain.h"
void cutsceneTextStart(
const cutsceneitem_t *item,
cutsceneitemdata_t *data
) {
uiTextboxMainSetText(item->text.text);
}
bool_t cutsceneTextUpdate(
const cutsceneitem_t *item,
cutsceneitemdata_t *data
) {
return !uiTextboxMainIsActive();
}
@@ -0,0 +1,41 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "dusk.h"
typedef struct cutsceneitem_s cutsceneitem_t;
typedef union cutsceneitemdata_u cutsceneitemdata_t;
#define CUTSCENE_TEXT_MAX_CHARS 256
typedef struct {
char_t text[CUTSCENE_TEXT_MAX_CHARS];
} cutscenetext_t;
/**
* Starts a text item -- shows the given text in UI_TEXTBOX_MAIN.
*
* @param item The cutscene item.
* @param data Runtime data storage.
*/
void cutsceneTextStart(
const cutsceneitem_t *item,
cutsceneitemdata_t *data
);
/**
* Updates a text item -- waits until UI_TEXTBOX_MAIN is dismissed.
*
* @param item The cutscene item.
* @param data Runtime data storage.
* @returns true once the textbox is no longer active.
*/
bool_t cutsceneTextUpdate(
const cutsceneitem_t *item,
cutsceneitemdata_t *data
);