Move cutscene item JSON parsing into per-item Load callbacks
Each cutscene item type now owns its own JSON parsing (a Load callback alongside its existing runtime callbacks), instead of one monolithic switch in assetcutsceneloader.c. Shared JSON field/enum decoding helpers move into a new rpg/cutscene/item/json/ module so per-type parsers stay small and colocated with the behavior they configure. Co-Authored-By: Claude Sonnet 5 <[email protected]>
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -9,7 +9,7 @@
|
||||
#include "asset/assetfile.h"
|
||||
#include "rpg/cutscene/cutscene.h"
|
||||
#include "rpg/cutscene/item/cutsceneitem.h"
|
||||
#include "rpg/overworld/worldpos.h"
|
||||
#include "rpg/cutscene/item/json/cutscenejsonpool.h"
|
||||
#include "yyjson.h"
|
||||
|
||||
// Above this, something is almost certainly wrong (or malicious) rather
|
||||
@@ -54,144 +54,15 @@ typedef struct {
|
||||
yyjson_doc *doc;
|
||||
} assetcutsceneoutput_t;
|
||||
|
||||
typedef struct {
|
||||
const char_t *name;
|
||||
int32_t value;
|
||||
} assetcutsceneenumentry_t;
|
||||
|
||||
typedef struct {
|
||||
const char_t *name;
|
||||
} assetcutsceneitemtypeentry_t;
|
||||
|
||||
/**
|
||||
* Looks up name in a {name, value} table via stringEquals - exact case,
|
||||
* used only for the top-level item "type" name (the one enum-ish field
|
||||
* the original tool's ITEM_TYPE dict looked up without .upper()).
|
||||
*
|
||||
* @param table Table to search.
|
||||
* @param tableCount Number of entries in table.
|
||||
* @param name Name to search for.
|
||||
* @param outValue Set to the matching entry's value on success.
|
||||
* @return true if a matching entry was found, false otherwise.
|
||||
*/
|
||||
bool_t assetCutsceneLookupEnum(
|
||||
const assetcutsceneenumentry_t *table,
|
||||
const size_t tableCount,
|
||||
const char_t *name,
|
||||
int32_t *outValue
|
||||
);
|
||||
|
||||
/**
|
||||
* Looks up name (exact case) against the item type table, which is indexed
|
||||
* directly by cutsceneitemtype_t rather than searched by value.
|
||||
*
|
||||
* @param name Name to search for.
|
||||
* @param outType Set to the matching item type on success.
|
||||
* @return true if a matching entry was found, false otherwise.
|
||||
*/
|
||||
bool_t assetCutsceneLookupItemType(
|
||||
const char_t *name,
|
||||
cutsceneitemtype_t *outType
|
||||
);
|
||||
|
||||
/**
|
||||
* Looks up name in a {name, value} table via stringCompareInsensitive -
|
||||
* every other enum-ish field (pause flags, entity/scene/battle/audio
|
||||
* enums, ...) is authored case-insensitively, matching the original
|
||||
* tool's ENUM_TABLE[name.upper()] lookups.
|
||||
*
|
||||
* @param table Table to search.
|
||||
* @param tableCount Number of entries in table.
|
||||
* @param name Name to search for.
|
||||
* @param outValue Set to the matching entry's value on success.
|
||||
* @return true if a matching entry was found, false otherwise.
|
||||
*/
|
||||
bool_t assetCutsceneLookupEnumInsensitive(
|
||||
const assetcutsceneenumentry_t *table,
|
||||
const size_t tableCount,
|
||||
const char_t *name,
|
||||
int32_t *outValue
|
||||
);
|
||||
|
||||
/**
|
||||
* Resolves a JSON value that's either an entity index sentinel string
|
||||
* ("INTERACT"/"INTERACTED") or a plain integer entity index.
|
||||
*
|
||||
* @param val JSON value to resolve (a string or a number).
|
||||
* @param outIndex Set to the resolved index on success.
|
||||
* @return true if val resolved to a valid index, false otherwise.
|
||||
*/
|
||||
bool_t assetCutsceneResolveEntityIndex(yyjson_val *val, uint8_t *outIndex);
|
||||
|
||||
/**
|
||||
* Resolves a JSON value that's either the "LAST_CREATED" map area sentinel
|
||||
* string or a plain integer area id.
|
||||
*
|
||||
* @param val JSON value to resolve (a string or a number).
|
||||
* @param outAreaId Set to the resolved area id on success.
|
||||
* @return true if val resolved to a valid area id, false otherwise.
|
||||
*/
|
||||
bool_t assetCutsceneResolveAreaId(yyjson_val *val, uint8_t *outAreaId);
|
||||
|
||||
/**
|
||||
* Reads obj[key] as a string (falling back to defaultValue if the key is
|
||||
* absent and defaultValue is non-NULL) into dest, a fixed-capacity
|
||||
* char_t[destCapacity] item field. Fails rather than truncating/asserting
|
||||
* if the string doesn't fit - this is untrusted, authored file content,
|
||||
* not an in-memory invariant.
|
||||
*
|
||||
* @param obj The item's JSON object.
|
||||
* @param key Field name to read.
|
||||
* @param defaultValue Value to use if key is absent, or NULL to require it.
|
||||
* @param dest Destination buffer.
|
||||
* @param destCapacity Capacity of dest, including the null terminator.
|
||||
* @return true on success, false if the field is missing (with no
|
||||
* default) or exceeds destCapacity.
|
||||
*/
|
||||
bool_t assetCutsceneCopyStringField(
|
||||
yyjson_val *obj,
|
||||
const char_t *key,
|
||||
const char_t *defaultValue,
|
||||
char_t *dest,
|
||||
const size_t destCapacity
|
||||
);
|
||||
|
||||
/**
|
||||
* Reads a 3-element JSON array of integers into a worldpos_t.
|
||||
*
|
||||
* @param arr JSON array value, expected to hold exactly 3 numbers.
|
||||
* @param out Set to the decoded position on success.
|
||||
* @return true if arr was a valid 3-element numeric array, false otherwise.
|
||||
*/
|
||||
bool_t assetCutsceneReadWorldPos(yyjson_val *arr, worldpos_t *out);
|
||||
|
||||
/**
|
||||
* Rounds size up to the next multiple of 4 - every pool entry starts
|
||||
* 4-byte aligned so worldpos_t/multi-byte reads out of it never trap on
|
||||
* alignment-sensitive hardware (e.g. PSP's MIPS core).
|
||||
*
|
||||
* @param size Size to round up.
|
||||
* @return size rounded up to the next multiple of 4.
|
||||
*/
|
||||
size_t assetCutscenePoolAlign(const size_t size);
|
||||
|
||||
/**
|
||||
* First pass over the parsed "items" array: sums the exact pool bytes
|
||||
* ENTITY_WALK_TO/MAP_AREA_WAIT items will need, so the real parse pass can
|
||||
* allocate the pool exactly once up front rather than growing/moving it
|
||||
* (which would dangle pointers already written into earlier items).
|
||||
*
|
||||
* @param itemsArr The cutscene's "items" JSON array.
|
||||
* @return Total pool bytes required (0 if none of the items need one).
|
||||
*/
|
||||
size_t assetCutsceneComputePoolSize(yyjson_val *itemsArr);
|
||||
|
||||
/**
|
||||
* Parses one cutscene item object into item, writing any pool-backed
|
||||
* array data (entityWalkTo positions, mapAreaWait areaIds) into pool at
|
||||
* *poolOffset and advancing it. Every field/enum name is validated as
|
||||
* real (untrusted, authored) file content - failures are real errors, not
|
||||
* asserts.
|
||||
* asserts. Dispatches to the matching type's Load callback (see
|
||||
* CUTSCENE_ITEM_CALLBACKS in rpg/cutscene/item/cutsceneitem.h) - the
|
||||
* per-type parsing logic itself lives there now, colocated with that
|
||||
* type's runtime behavior.
|
||||
*
|
||||
* @param loading Loading information for the asset being loaded.
|
||||
* @param itemObj The item's JSON object.
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
||||
PUBLIC
|
||||
cutsceneitem.c
|
||||
cutsceneitembase.c
|
||||
cutscenecallback.c
|
||||
cutsceneprint.c
|
||||
)
|
||||
@@ -18,3 +19,4 @@ add_subdirectory(ui)
|
||||
add_subdirectory(battle)
|
||||
add_subdirectory(save)
|
||||
add_subdirectory(audio)
|
||||
add_subdirectory(json)
|
||||
|
||||
@@ -7,6 +7,9 @@
|
||||
|
||||
#include "rpg/cutscene/item/cutsceneitem.h"
|
||||
#include "audio/mixer/audiomixer.h"
|
||||
#include "rpg/cutscene/item/json/cutscenejsonaudiochannel.h"
|
||||
#include "rpg/cutscene/item/json/cutscenejsoneasing.h"
|
||||
#include "rpg/cutscene/item/json/cutscenejsonfield.h"
|
||||
|
||||
void cutsceneAudioFadeStart(
|
||||
const cutsceneitem_t *item,
|
||||
@@ -27,3 +30,32 @@ bool_t cutsceneAudioFadeUpdate(
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
errorret_t cutsceneAudioFadeLoad(
|
||||
yyjson_val *itemObj,
|
||||
cutsceneitem_t *item,
|
||||
uint8_t *pool,
|
||||
size_t *poolOffset
|
||||
) {
|
||||
audiomixerchannel_t channelValue;
|
||||
if(!cutsceneJsonLookupAudioChannel(
|
||||
yyjson_get_str(yyjson_obj_get(itemObj, "channel")), &channelValue
|
||||
)) {
|
||||
errorThrow("Cutscene item (AUDIO_FADE): invalid 'channel'");
|
||||
}
|
||||
item->audioFade.channel = channelValue;
|
||||
item->audioFade.from = cutsceneJsonGetFloat(itemObj, "from", 0.0f);
|
||||
item->audioFade.to = cutsceneJsonGetFloat(itemObj, "to", 0.0f);
|
||||
item->audioFade.duration = cutsceneJsonGetFloat(itemObj, "duration", 0.0f);
|
||||
|
||||
const char_t *easingName =
|
||||
yyjson_get_str(yyjson_obj_get(itemObj, "easing"));
|
||||
easingtype_t easingValue = EASING_LINEAR;
|
||||
if(easingName != NULL &&
|
||||
!cutsceneJsonLookupEasing(easingName, &easingValue)) {
|
||||
errorThrow("Cutscene item (AUDIO_FADE): invalid 'easing'");
|
||||
}
|
||||
item->audioFade.easing = easingValue;
|
||||
|
||||
errorOk();
|
||||
}
|
||||
|
||||
@@ -8,9 +8,7 @@
|
||||
#pragma once
|
||||
#include "audio/mixer/audiomixerchannel.h"
|
||||
#include "animation/easing.h"
|
||||
|
||||
typedef struct cutsceneitem_s cutsceneitem_t;
|
||||
typedef union cutsceneitemdata_u cutsceneitemdata_t;
|
||||
#include "rpg/cutscene/item/cutsceneitembase.h"
|
||||
|
||||
typedef struct {
|
||||
audiomixerchannel_t channel;
|
||||
@@ -44,3 +42,19 @@ bool_t cutsceneAudioFadeUpdate(
|
||||
const cutsceneitem_t *item,
|
||||
cutsceneitemdata_t *data
|
||||
);
|
||||
|
||||
/**
|
||||
* Parses an AUDIO_FADE cutscene item's JSON fields into item.
|
||||
*
|
||||
* @param itemObj The item's JSON object.
|
||||
* @param item Destination item, already zeroed by the caller.
|
||||
* @param pool Unused (AUDIO_FADE needs no pool storage).
|
||||
* @param poolOffset Unused (AUDIO_FADE needs no pool storage).
|
||||
* @return Error code indicating success or failure of the parse.
|
||||
*/
|
||||
errorret_t cutsceneAudioFadeLoad(
|
||||
yyjson_val *itemObj,
|
||||
cutsceneitem_t *item,
|
||||
uint8_t *pool,
|
||||
size_t *poolOffset
|
||||
);
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#include "rpg/cutscene/item/cutsceneitem.h"
|
||||
#include "audio/mixer/audiomixer.h"
|
||||
#include "rpg/cutscene/item/json/cutscenejsonaudiochannel.h"
|
||||
|
||||
bool_t cutsceneAudioFadeWaitUpdate(
|
||||
const cutsceneitem_t *item,
|
||||
@@ -14,3 +15,12 @@ bool_t cutsceneAudioFadeWaitUpdate(
|
||||
) {
|
||||
return !audioMixerIsFading(item->audioFadeWaitChannel);
|
||||
}
|
||||
|
||||
errorret_t cutsceneAudioFadeWaitLoad(
|
||||
yyjson_val *itemObj,
|
||||
cutsceneitem_t *item,
|
||||
uint8_t *pool,
|
||||
size_t *poolOffset
|
||||
) {
|
||||
return cutsceneJsonLoadAudioChannelOnly(itemObj, &item->audioFadeWaitChannel);
|
||||
}
|
||||
|
||||
@@ -7,9 +7,7 @@
|
||||
|
||||
#pragma once
|
||||
#include "audio/mixer/audiomixerchannel.h"
|
||||
|
||||
typedef struct cutsceneitem_s cutsceneitem_t;
|
||||
typedef union cutsceneitemdata_u cutsceneitemdata_t;
|
||||
#include "rpg/cutscene/item/cutsceneitembase.h"
|
||||
|
||||
/**
|
||||
* Updates an audio fade-wait step, completing once the watched channel's
|
||||
@@ -24,3 +22,19 @@ bool_t cutsceneAudioFadeWaitUpdate(
|
||||
const cutsceneitem_t *item,
|
||||
cutsceneitemdata_t *data
|
||||
);
|
||||
|
||||
/**
|
||||
* Parses an AUDIO_FADE_WAIT cutscene item's JSON fields into item.
|
||||
*
|
||||
* @param itemObj The item's JSON object.
|
||||
* @param item Destination item, already zeroed by the caller.
|
||||
* @param pool Unused (AUDIO_FADE_WAIT needs no pool storage).
|
||||
* @param poolOffset Unused (AUDIO_FADE_WAIT needs no pool storage).
|
||||
* @return Error code indicating success or failure of the parse.
|
||||
*/
|
||||
errorret_t cutsceneAudioFadeWaitLoad(
|
||||
yyjson_val *itemObj,
|
||||
cutsceneitem_t *item,
|
||||
uint8_t *pool,
|
||||
size_t *poolOffset
|
||||
);
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#include "rpg/cutscene/item/cutsceneitem.h"
|
||||
#include "audio/mixer/audiomixer.h"
|
||||
#include "rpg/cutscene/item/json/cutscenejsonaudiochannel.h"
|
||||
|
||||
void cutsceneAudioPauseStart(
|
||||
const cutsceneitem_t *item,
|
||||
@@ -21,3 +22,12 @@ bool_t cutsceneAudioPauseUpdate(
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
errorret_t cutsceneAudioPauseLoad(
|
||||
yyjson_val *itemObj,
|
||||
cutsceneitem_t *item,
|
||||
uint8_t *pool,
|
||||
size_t *poolOffset
|
||||
) {
|
||||
return cutsceneJsonLoadAudioChannelOnly(itemObj, &item->audioPauseChannel);
|
||||
}
|
||||
|
||||
@@ -7,9 +7,7 @@
|
||||
|
||||
#pragma once
|
||||
#include "audio/mixer/audiomixerchannel.h"
|
||||
|
||||
typedef struct cutsceneitem_s cutsceneitem_t;
|
||||
typedef union cutsceneitemdata_u cutsceneitemdata_t;
|
||||
#include "rpg/cutscene/item/cutsceneitembase.h"
|
||||
|
||||
/**
|
||||
* Starts an audio pause step (pauses the channel immediately).
|
||||
@@ -33,3 +31,19 @@ bool_t cutsceneAudioPauseUpdate(
|
||||
const cutsceneitem_t *item,
|
||||
cutsceneitemdata_t *data
|
||||
);
|
||||
|
||||
/**
|
||||
* Parses an AUDIO_PAUSE cutscene item's JSON fields into item.
|
||||
*
|
||||
* @param itemObj The item's JSON object.
|
||||
* @param item Destination item, already zeroed by the caller.
|
||||
* @param pool Unused (AUDIO_PAUSE needs no pool storage).
|
||||
* @param poolOffset Unused (AUDIO_PAUSE needs no pool storage).
|
||||
* @return Error code indicating success or failure of the parse.
|
||||
*/
|
||||
errorret_t cutsceneAudioPauseLoad(
|
||||
yyjson_val *itemObj,
|
||||
cutsceneitem_t *item,
|
||||
uint8_t *pool,
|
||||
size_t *poolOffset
|
||||
);
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
*/
|
||||
|
||||
#include "rpg/cutscene/item/cutsceneitem.h"
|
||||
#include "rpg/cutscene/item/json/cutscenejsonaudiochannel.h"
|
||||
#include "rpg/cutscene/item/json/cutscenejsonfield.h"
|
||||
|
||||
void cutsceneAudioPlayStart(
|
||||
const cutsceneitem_t *item,
|
||||
@@ -29,3 +31,34 @@ bool_t cutsceneAudioPlayUpdate(
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
errorret_t cutsceneAudioPlayLoad(
|
||||
yyjson_val *itemObj,
|
||||
cutsceneitem_t *item,
|
||||
uint8_t *pool,
|
||||
size_t *poolOffset
|
||||
) {
|
||||
if(!cutsceneJsonCopyString(
|
||||
itemObj, "file", NULL, item->audioPlay.file, AUDIO_PATH_MAX
|
||||
)) {
|
||||
errorThrow("Cutscene item (AUDIO_PLAY): missing/too-long 'file'");
|
||||
}
|
||||
audiomixerchannel_t channelValue;
|
||||
if(!cutsceneJsonLookupAudioChannel(
|
||||
yyjson_get_str(yyjson_obj_get(itemObj, "channel")), &channelValue
|
||||
)) {
|
||||
errorThrow("Cutscene item (AUDIO_PLAY): invalid 'channel'");
|
||||
}
|
||||
item->audioPlay.channel = channelValue;
|
||||
|
||||
item->audioPlay.volume = cutsceneJsonGetFloat(itemObj, "volume", 1.0f);
|
||||
item->audioPlay.pan = cutsceneJsonGetFloat(itemObj, "pan", 0.0f);
|
||||
item->audioPlay.looping = cutsceneJsonGetBool(itemObj, "looping", false);
|
||||
item->audioPlay.loopCount =
|
||||
(uint8_t)cutsceneJsonGetInt(itemObj, "loopCount", 0);
|
||||
item->audioPlay.loopStart =
|
||||
cutsceneJsonGetFloat(itemObj, "loopStart", -1.0f);
|
||||
item->audioPlay.loopTo = cutsceneJsonGetFloat(itemObj, "loopTo", 0.0f);
|
||||
|
||||
errorOk();
|
||||
}
|
||||
|
||||
@@ -7,9 +7,7 @@
|
||||
|
||||
#pragma once
|
||||
#include "audio/mixer/audiomixer.h"
|
||||
|
||||
typedef struct cutsceneitem_s cutsceneitem_t;
|
||||
typedef union cutsceneitemdata_u cutsceneitemdata_t;
|
||||
#include "rpg/cutscene/item/cutsceneitembase.h"
|
||||
|
||||
typedef struct {
|
||||
char_t file[AUDIO_PATH_MAX];
|
||||
@@ -46,3 +44,19 @@ bool_t cutsceneAudioPlayUpdate(
|
||||
const cutsceneitem_t *item,
|
||||
cutsceneitemdata_t *data
|
||||
);
|
||||
|
||||
/**
|
||||
* Parses an AUDIO_PLAY cutscene item's JSON fields into item.
|
||||
*
|
||||
* @param itemObj The item's JSON object.
|
||||
* @param item Destination item, already zeroed by the caller.
|
||||
* @param pool Unused (AUDIO_PLAY needs no pool storage).
|
||||
* @param poolOffset Unused (AUDIO_PLAY needs no pool storage).
|
||||
* @return Error code indicating success or failure of the parse.
|
||||
*/
|
||||
errorret_t cutsceneAudioPlayLoad(
|
||||
yyjson_val *itemObj,
|
||||
cutsceneitem_t *item,
|
||||
uint8_t *pool,
|
||||
size_t *poolOffset
|
||||
);
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#include "rpg/cutscene/item/cutsceneitem.h"
|
||||
#include "audio/mixer/audiomixer.h"
|
||||
#include "rpg/cutscene/item/json/cutscenejsonaudiochannel.h"
|
||||
|
||||
void cutsceneAudioResumeStart(
|
||||
const cutsceneitem_t *item,
|
||||
@@ -21,3 +22,12 @@ bool_t cutsceneAudioResumeUpdate(
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
errorret_t cutsceneAudioResumeLoad(
|
||||
yyjson_val *itemObj,
|
||||
cutsceneitem_t *item,
|
||||
uint8_t *pool,
|
||||
size_t *poolOffset
|
||||
) {
|
||||
return cutsceneJsonLoadAudioChannelOnly(itemObj, &item->audioResumeChannel);
|
||||
}
|
||||
|
||||
@@ -7,9 +7,7 @@
|
||||
|
||||
#pragma once
|
||||
#include "audio/mixer/audiomixerchannel.h"
|
||||
|
||||
typedef struct cutsceneitem_s cutsceneitem_t;
|
||||
typedef union cutsceneitemdata_u cutsceneitemdata_t;
|
||||
#include "rpg/cutscene/item/cutsceneitembase.h"
|
||||
|
||||
/**
|
||||
* Starts an audio resume step (resumes the channel immediately).
|
||||
@@ -33,3 +31,19 @@ bool_t cutsceneAudioResumeUpdate(
|
||||
const cutsceneitem_t *item,
|
||||
cutsceneitemdata_t *data
|
||||
);
|
||||
|
||||
/**
|
||||
* Parses an AUDIO_RESUME cutscene item's JSON fields into item.
|
||||
*
|
||||
* @param itemObj The item's JSON object.
|
||||
* @param item Destination item, already zeroed by the caller.
|
||||
* @param pool Unused (AUDIO_RESUME needs no pool storage).
|
||||
* @param poolOffset Unused (AUDIO_RESUME needs no pool storage).
|
||||
* @return Error code indicating success or failure of the parse.
|
||||
*/
|
||||
errorret_t cutsceneAudioResumeLoad(
|
||||
yyjson_val *itemObj,
|
||||
cutsceneitem_t *item,
|
||||
uint8_t *pool,
|
||||
size_t *poolOffset
|
||||
);
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
|
||||
#include "rpg/cutscene/item/cutsceneitem.h"
|
||||
#include "audio/mixer/audiomixer.h"
|
||||
#include "rpg/cutscene/item/json/cutscenejsonaudiochannel.h"
|
||||
#include "rpg/cutscene/item/json/cutscenejsonfield.h"
|
||||
|
||||
void cutsceneAudioSetStart(
|
||||
const cutsceneitem_t *item,
|
||||
@@ -28,3 +30,27 @@ bool_t cutsceneAudioSetUpdate(
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
errorret_t cutsceneAudioSetLoad(
|
||||
yyjson_val *itemObj,
|
||||
cutsceneitem_t *item,
|
||||
uint8_t *pool,
|
||||
size_t *poolOffset
|
||||
) {
|
||||
audiomixerchannel_t channelValue;
|
||||
if(!cutsceneJsonLookupAudioChannel(
|
||||
yyjson_get_str(yyjson_obj_get(itemObj, "channel")), &channelValue
|
||||
)) {
|
||||
errorThrow("Cutscene item (AUDIO_SET): invalid 'channel'");
|
||||
}
|
||||
item->audioSet.channel = channelValue;
|
||||
item->audioSet.pan = cutsceneJsonGetFloat(itemObj, "pan", 0.0f);
|
||||
item->audioSet.looping = cutsceneJsonGetBool(itemObj, "looping", true);
|
||||
item->audioSet.loopCount =
|
||||
(uint8_t)cutsceneJsonGetInt(itemObj, "loopCount", 0);
|
||||
item->audioSet.loopStart =
|
||||
cutsceneJsonGetFloat(itemObj, "loopStart", -1.0f);
|
||||
item->audioSet.loopTo = cutsceneJsonGetFloat(itemObj, "loopTo", 0.0f);
|
||||
|
||||
errorOk();
|
||||
}
|
||||
|
||||
@@ -7,9 +7,7 @@
|
||||
|
||||
#pragma once
|
||||
#include "audio/mixer/audiomixerchannel.h"
|
||||
|
||||
typedef struct cutsceneitem_s cutsceneitem_t;
|
||||
typedef union cutsceneitemdata_u cutsceneitemdata_t;
|
||||
#include "rpg/cutscene/item/cutsceneitembase.h"
|
||||
|
||||
typedef struct {
|
||||
audiomixerchannel_t channel;
|
||||
@@ -45,3 +43,19 @@ bool_t cutsceneAudioSetUpdate(
|
||||
const cutsceneitem_t *item,
|
||||
cutsceneitemdata_t *data
|
||||
);
|
||||
|
||||
/**
|
||||
* Parses an AUDIO_SET cutscene item's JSON fields into item.
|
||||
*
|
||||
* @param itemObj The item's JSON object.
|
||||
* @param item Destination item, already zeroed by the caller.
|
||||
* @param pool Unused (AUDIO_SET needs no pool storage).
|
||||
* @param poolOffset Unused (AUDIO_SET needs no pool storage).
|
||||
* @return Error code indicating success or failure of the parse.
|
||||
*/
|
||||
errorret_t cutsceneAudioSetLoad(
|
||||
yyjson_val *itemObj,
|
||||
cutsceneitem_t *item,
|
||||
uint8_t *pool,
|
||||
size_t *poolOffset
|
||||
);
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
|
||||
#include "rpg/cutscene/item/cutsceneitem.h"
|
||||
#include "audio/mixer/audiomixer.h"
|
||||
#include "rpg/cutscene/item/json/cutscenejsonaudiochannel.h"
|
||||
#include "rpg/cutscene/item/json/cutscenejsonfield.h"
|
||||
|
||||
void cutsceneAudioSetLoopStart(
|
||||
const cutsceneitem_t *item,
|
||||
@@ -27,3 +29,26 @@ bool_t cutsceneAudioSetLoopUpdate(
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
errorret_t cutsceneAudioSetLoopLoad(
|
||||
yyjson_val *itemObj,
|
||||
cutsceneitem_t *item,
|
||||
uint8_t *pool,
|
||||
size_t *poolOffset
|
||||
) {
|
||||
audiomixerchannel_t channelValue;
|
||||
if(!cutsceneJsonLookupAudioChannel(
|
||||
yyjson_get_str(yyjson_obj_get(itemObj, "channel")), &channelValue
|
||||
)) {
|
||||
errorThrow("Cutscene item (AUDIO_SET_LOOP): invalid 'channel'");
|
||||
}
|
||||
item->audioSetLoop.channel = channelValue;
|
||||
item->audioSetLoop.looping = cutsceneJsonGetBool(itemObj, "looping", true);
|
||||
item->audioSetLoop.loopCount =
|
||||
(uint8_t)cutsceneJsonGetInt(itemObj, "loopCount", 0);
|
||||
item->audioSetLoop.loopStart =
|
||||
cutsceneJsonGetFloat(itemObj, "loopStart", -1.0f);
|
||||
item->audioSetLoop.loopTo = cutsceneJsonGetFloat(itemObj, "loopTo", 0.0f);
|
||||
|
||||
errorOk();
|
||||
}
|
||||
|
||||
@@ -7,9 +7,7 @@
|
||||
|
||||
#pragma once
|
||||
#include "audio/mixer/audiomixerchannel.h"
|
||||
|
||||
typedef struct cutsceneitem_s cutsceneitem_t;
|
||||
typedef union cutsceneitemdata_u cutsceneitemdata_t;
|
||||
#include "rpg/cutscene/item/cutsceneitembase.h"
|
||||
|
||||
typedef struct {
|
||||
audiomixerchannel_t channel;
|
||||
@@ -42,3 +40,19 @@ bool_t cutsceneAudioSetLoopUpdate(
|
||||
const cutsceneitem_t *item,
|
||||
cutsceneitemdata_t *data
|
||||
);
|
||||
|
||||
/**
|
||||
* Parses an AUDIO_SET_LOOP cutscene item's JSON fields into item.
|
||||
*
|
||||
* @param itemObj The item's JSON object.
|
||||
* @param item Destination item, already zeroed by the caller.
|
||||
* @param pool Unused (AUDIO_SET_LOOP needs no pool storage).
|
||||
* @param poolOffset Unused (AUDIO_SET_LOOP needs no pool storage).
|
||||
* @return Error code indicating success or failure of the parse.
|
||||
*/
|
||||
errorret_t cutsceneAudioSetLoopLoad(
|
||||
yyjson_val *itemObj,
|
||||
cutsceneitem_t *item,
|
||||
uint8_t *pool,
|
||||
size_t *poolOffset
|
||||
);
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
|
||||
#include "rpg/cutscene/item/cutsceneitem.h"
|
||||
#include "audio/mixer/audiomixer.h"
|
||||
#include "rpg/cutscene/item/json/cutscenejsonaudiochannel.h"
|
||||
#include "rpg/cutscene/item/json/cutscenejsonfield.h"
|
||||
|
||||
void cutsceneAudioSetPanStart(
|
||||
const cutsceneitem_t *item,
|
||||
@@ -21,3 +23,21 @@ bool_t cutsceneAudioSetPanUpdate(
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
errorret_t cutsceneAudioSetPanLoad(
|
||||
yyjson_val *itemObj,
|
||||
cutsceneitem_t *item,
|
||||
uint8_t *pool,
|
||||
size_t *poolOffset
|
||||
) {
|
||||
audiomixerchannel_t channelValue;
|
||||
if(!cutsceneJsonLookupAudioChannel(
|
||||
yyjson_get_str(yyjson_obj_get(itemObj, "channel")), &channelValue
|
||||
)) {
|
||||
errorThrow("Cutscene item (AUDIO_SET_PAN): invalid 'channel'");
|
||||
}
|
||||
item->audioSetPan.channel = channelValue;
|
||||
item->audioSetPan.pan = cutsceneJsonGetFloat(itemObj, "pan", 0.0f);
|
||||
|
||||
errorOk();
|
||||
}
|
||||
|
||||
@@ -7,9 +7,7 @@
|
||||
|
||||
#pragma once
|
||||
#include "audio/mixer/audiomixerchannel.h"
|
||||
|
||||
typedef struct cutsceneitem_s cutsceneitem_t;
|
||||
typedef union cutsceneitemdata_u cutsceneitemdata_t;
|
||||
#include "rpg/cutscene/item/cutsceneitembase.h"
|
||||
|
||||
typedef struct {
|
||||
audiomixerchannel_t channel;
|
||||
@@ -39,3 +37,19 @@ bool_t cutsceneAudioSetPanUpdate(
|
||||
const cutsceneitem_t *item,
|
||||
cutsceneitemdata_t *data
|
||||
);
|
||||
|
||||
/**
|
||||
* Parses an AUDIO_SET_PAN cutscene item's JSON fields into item.
|
||||
*
|
||||
* @param itemObj The item's JSON object.
|
||||
* @param item Destination item, already zeroed by the caller.
|
||||
* @param pool Unused (AUDIO_SET_PAN needs no pool storage).
|
||||
* @param poolOffset Unused (AUDIO_SET_PAN needs no pool storage).
|
||||
* @return Error code indicating success or failure of the parse.
|
||||
*/
|
||||
errorret_t cutsceneAudioSetPanLoad(
|
||||
yyjson_val *itemObj,
|
||||
cutsceneitem_t *item,
|
||||
uint8_t *pool,
|
||||
size_t *poolOffset
|
||||
);
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#include "rpg/cutscene/item/cutsceneitem.h"
|
||||
#include "audio/mixer/audiomixer.h"
|
||||
#include "rpg/cutscene/item/json/cutscenejsonaudiochannel.h"
|
||||
|
||||
void cutsceneAudioStopStart(
|
||||
const cutsceneitem_t *item,
|
||||
@@ -21,3 +22,12 @@ bool_t cutsceneAudioStopUpdate(
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
errorret_t cutsceneAudioStopLoad(
|
||||
yyjson_val *itemObj,
|
||||
cutsceneitem_t *item,
|
||||
uint8_t *pool,
|
||||
size_t *poolOffset
|
||||
) {
|
||||
return cutsceneJsonLoadAudioChannelOnly(itemObj, &item->audioStopChannel);
|
||||
}
|
||||
|
||||
@@ -7,9 +7,7 @@
|
||||
|
||||
#pragma once
|
||||
#include "audio/mixer/audiomixerchannel.h"
|
||||
|
||||
typedef struct cutsceneitem_s cutsceneitem_t;
|
||||
typedef union cutsceneitemdata_u cutsceneitemdata_t;
|
||||
#include "rpg/cutscene/item/cutsceneitembase.h"
|
||||
|
||||
/**
|
||||
* Starts an audio stop step (stops the channel immediately).
|
||||
@@ -33,3 +31,19 @@ bool_t cutsceneAudioStopUpdate(
|
||||
const cutsceneitem_t *item,
|
||||
cutsceneitemdata_t *data
|
||||
);
|
||||
|
||||
/**
|
||||
* Parses an AUDIO_STOP cutscene item's JSON fields into item.
|
||||
*
|
||||
* @param itemObj The item's JSON object.
|
||||
* @param item Destination item, already zeroed by the caller.
|
||||
* @param pool Unused (AUDIO_STOP needs no pool storage).
|
||||
* @param poolOffset Unused (AUDIO_STOP needs no pool storage).
|
||||
* @return Error code indicating success or failure of the parse.
|
||||
*/
|
||||
errorret_t cutsceneAudioStopLoad(
|
||||
yyjson_val *itemObj,
|
||||
cutsceneitem_t *item,
|
||||
uint8_t *pool,
|
||||
size_t *poolOffset
|
||||
);
|
||||
|
||||
@@ -23,3 +23,17 @@ bool_t cutsceneBattleForceActionUpdate(
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
errorret_t cutsceneBattleForceActionLoad(
|
||||
yyjson_val *itemObj,
|
||||
cutsceneitem_t *item,
|
||||
uint8_t *pool,
|
||||
size_t *poolOffset
|
||||
) {
|
||||
item->battleForceAction.fighterIndex =
|
||||
(uint8_t)yyjson_get_int(yyjson_obj_get(itemObj, "fighterIndex"));
|
||||
item->battleForceAction.targetIndex =
|
||||
(uint8_t)yyjson_get_int(yyjson_obj_get(itemObj, "targetIndex"));
|
||||
|
||||
errorOk();
|
||||
}
|
||||
|
||||
@@ -7,15 +7,13 @@
|
||||
|
||||
#pragma once
|
||||
#include "rpg/battle/battle.h"
|
||||
#include "rpg/cutscene/item/cutsceneitembase.h"
|
||||
|
||||
typedef struct {
|
||||
uint8_t fighterIndex;
|
||||
uint8_t targetIndex;
|
||||
} cutscenebattleforceaction_t;
|
||||
|
||||
typedef struct cutsceneitem_s cutsceneitem_t;
|
||||
typedef union cutsceneitemdata_u cutsceneitemdata_t;
|
||||
|
||||
/**
|
||||
* Starts a battle force-action step: immediately queues an attack for the
|
||||
* given fighter against the given target, bypassing normal player/AI
|
||||
@@ -40,3 +38,19 @@ bool_t cutsceneBattleForceActionUpdate(
|
||||
const cutsceneitem_t *item,
|
||||
cutsceneitemdata_t *data
|
||||
);
|
||||
|
||||
/**
|
||||
* Parses a BATTLE_FORCE_ACTION cutscene item's JSON fields into item.
|
||||
*
|
||||
* @param itemObj The item's JSON object.
|
||||
* @param item Destination item, already zeroed by the caller.
|
||||
* @param pool Unused (BATTLE_FORCE_ACTION needs no pool storage).
|
||||
* @param poolOffset Unused (BATTLE_FORCE_ACTION needs no pool storage).
|
||||
* @return Error code indicating success or failure of the parse.
|
||||
*/
|
||||
errorret_t cutsceneBattleForceActionLoad(
|
||||
yyjson_val *itemObj,
|
||||
cutsceneitem_t *item,
|
||||
uint8_t *pool,
|
||||
size_t *poolOffset
|
||||
);
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
#include "rpg/cutscene/item/cutsceneitem.h"
|
||||
#include "rpg/cutscene/item/json/cutscenejsonbattlestate.h"
|
||||
|
||||
bool_t cutsceneBattleWaitStateUpdate(
|
||||
const cutsceneitem_t *item,
|
||||
@@ -13,3 +14,20 @@ bool_t cutsceneBattleWaitStateUpdate(
|
||||
) {
|
||||
return BATTLE.state == item->battleWaitState.state;
|
||||
}
|
||||
|
||||
errorret_t cutsceneBattleWaitStateLoad(
|
||||
yyjson_val *itemObj,
|
||||
cutsceneitem_t *item,
|
||||
uint8_t *pool,
|
||||
size_t *poolOffset
|
||||
) {
|
||||
battlestate_t stateValue;
|
||||
if(!cutsceneJsonLookupBattleState(
|
||||
yyjson_get_str(yyjson_obj_get(itemObj, "state")), &stateValue
|
||||
)) {
|
||||
errorThrow("Cutscene item (BATTLE_WAIT_STATE): invalid 'state'");
|
||||
}
|
||||
item->battleWaitState.state = stateValue;
|
||||
|
||||
errorOk();
|
||||
}
|
||||
|
||||
@@ -7,14 +7,12 @@
|
||||
|
||||
#pragma once
|
||||
#include "rpg/battle/battle.h"
|
||||
#include "rpg/cutscene/item/cutsceneitembase.h"
|
||||
|
||||
typedef struct {
|
||||
battlestate_t state;
|
||||
} cutscenebattlewaitstate_t;
|
||||
|
||||
typedef struct cutsceneitem_s cutsceneitem_t;
|
||||
typedef union cutsceneitemdata_u cutsceneitemdata_t;
|
||||
|
||||
/**
|
||||
* Updates a battle wait-state step, completing once BATTLE.state reaches
|
||||
* the watched state. Has no Start callback -- there's nothing to do until
|
||||
@@ -28,3 +26,19 @@ bool_t cutsceneBattleWaitStateUpdate(
|
||||
const cutsceneitem_t *item,
|
||||
cutsceneitemdata_t *data
|
||||
);
|
||||
|
||||
/**
|
||||
* Parses a BATTLE_WAIT_STATE cutscene item's JSON fields into item.
|
||||
*
|
||||
* @param itemObj The item's JSON object.
|
||||
* @param item Destination item, already zeroed by the caller.
|
||||
* @param pool Unused (BATTLE_WAIT_STATE needs no pool storage).
|
||||
* @param poolOffset Unused (BATTLE_WAIT_STATE needs no pool storage).
|
||||
* @return Error code indicating success or failure of the parse.
|
||||
*/
|
||||
errorret_t cutsceneBattleWaitStateLoad(
|
||||
yyjson_val *itemObj,
|
||||
cutsceneitem_t *item,
|
||||
uint8_t *pool,
|
||||
size_t *poolOffset
|
||||
);
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
#include "rpg/cutscene/item/cutsceneitem.h"
|
||||
#include "rpg/battle/party.h"
|
||||
#include "scene/scene.h"
|
||||
#include "rpg/cutscene/item/json/cutscenejsonbattleencounter.h"
|
||||
#include "rpg/cutscene/item/json/cutscenejsonfield.h"
|
||||
|
||||
void cutsceneStartBattleStart(
|
||||
const cutsceneitem_t *item,
|
||||
@@ -69,3 +71,63 @@ bool_t cutsceneStartBattleUpdate(
|
||||
battleDispose();
|
||||
return true;
|
||||
}
|
||||
|
||||
errorret_t cutsceneStartBattleLoad(
|
||||
yyjson_val *itemObj,
|
||||
cutsceneitem_t *item,
|
||||
uint8_t *pool,
|
||||
size_t *poolOffset
|
||||
) {
|
||||
battleencountertype_t encounterValue;
|
||||
if(!cutsceneJsonLookupBattleEncounter(
|
||||
yyjson_get_str(yyjson_obj_get(itemObj, "encounterType")), &encounterValue
|
||||
)) {
|
||||
errorThrow("Cutscene item (START_BATTLE): invalid 'encounterType'");
|
||||
}
|
||||
item->startBattle.encounterType = encounterValue;
|
||||
|
||||
item->startBattle.fleeAvailable =
|
||||
cutsceneJsonGetBool(itemObj, "fleeAvailable", true);
|
||||
|
||||
yyjson_val *enemies = yyjson_obj_get(itemObj, "enemies");
|
||||
size_t enemyCount = yyjson_arr_size(enemies);
|
||||
if(!yyjson_is_arr(enemies) || enemyCount == 0 ||
|
||||
enemyCount > CUTSCENE_START_BATTLE_ENEMY_COUNT_MAX) {
|
||||
errorThrow(
|
||||
"Cutscene item (START_BATTLE): 'enemies' must have 1-%u entries",
|
||||
(uint32_t)CUTSCENE_START_BATTLE_ENEMY_COUNT_MAX
|
||||
);
|
||||
}
|
||||
item->startBattle.enemyCount = (uint8_t)enemyCount;
|
||||
|
||||
yyjson_arr_iter iter = yyjson_arr_iter_with(enemies);
|
||||
yyjson_val *enemyVal;
|
||||
size_t e = 0;
|
||||
while((enemyVal = yyjson_arr_iter_next(&iter)) != NULL) {
|
||||
yyjson_val *stats = yyjson_obj_get(enemyVal, "stats");
|
||||
if(!yyjson_is_obj(stats)) {
|
||||
errorThrow(
|
||||
"Cutscene item (START_BATTLE): enemies[%u] is missing 'stats'",
|
||||
(uint32_t)e
|
||||
);
|
||||
}
|
||||
cutscenestartbattleenemy_t *enemy = &item->startBattle.enemies[e];
|
||||
enemy->stats.attack =
|
||||
(uint16_t)yyjson_get_int(yyjson_obj_get(stats, "attack"));
|
||||
enemy->stats.defense =
|
||||
(uint16_t)yyjson_get_int(yyjson_obj_get(stats, "defense"));
|
||||
enemy->stats.magic =
|
||||
(uint16_t)yyjson_get_int(yyjson_obj_get(stats, "magic"));
|
||||
enemy->stats.speed =
|
||||
(uint16_t)yyjson_get_int(yyjson_obj_get(stats, "speed"));
|
||||
enemy->stats.luck =
|
||||
(uint16_t)yyjson_get_int(yyjson_obj_get(stats, "luck"));
|
||||
enemy->healthMax =
|
||||
(uint16_t)yyjson_get_int(yyjson_obj_get(enemyVal, "healthMax"));
|
||||
enemy->mpMax =
|
||||
(uint16_t)yyjson_get_int(yyjson_obj_get(enemyVal, "mpMax"));
|
||||
e++;
|
||||
}
|
||||
|
||||
errorOk();
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#pragma once
|
||||
#include "rpg/battle/battle.h"
|
||||
#include "rpg/cutscene/item/cutsceneitembase.h"
|
||||
|
||||
#define CUTSCENE_START_BATTLE_ENEMY_COUNT_MAX 4
|
||||
|
||||
@@ -16,9 +17,6 @@ typedef struct {
|
||||
uint16_t mpMax;
|
||||
} cutscenestartbattleenemy_t;
|
||||
|
||||
typedef struct cutsceneitem_s cutsceneitem_t;
|
||||
typedef union cutsceneitemdata_u cutsceneitemdata_t;
|
||||
|
||||
typedef struct {
|
||||
battleencountertype_t encounterType;
|
||||
bool_t fleeAvailable;
|
||||
@@ -51,3 +49,19 @@ bool_t cutsceneStartBattleUpdate(
|
||||
const cutsceneitem_t *item,
|
||||
cutsceneitemdata_t *data
|
||||
);
|
||||
|
||||
/**
|
||||
* Parses a START_BATTLE cutscene item's JSON fields into item.
|
||||
*
|
||||
* @param itemObj The item's JSON object.
|
||||
* @param item Destination item, already zeroed by the caller.
|
||||
* @param pool Unused (START_BATTLE needs no pool storage).
|
||||
* @param poolOffset Unused (START_BATTLE needs no pool storage).
|
||||
* @return Error code indicating success or failure of the parse.
|
||||
*/
|
||||
errorret_t cutsceneStartBattleLoad(
|
||||
yyjson_val *itemObj,
|
||||
cutsceneitem_t *item,
|
||||
uint8_t *pool,
|
||||
size_t *poolOffset
|
||||
);
|
||||
|
||||
@@ -6,12 +6,10 @@
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "rpg/cutscene/item/cutsceneitembase.h"
|
||||
#include "cutscenewait.h"
|
||||
#include "rpg/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
|
||||
|
||||
|
||||
@@ -6,10 +6,7 @@
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "dusk.h"
|
||||
|
||||
typedef struct cutsceneitem_s cutsceneitem_t;
|
||||
typedef union cutsceneitemdata_u cutsceneitemdata_t;
|
||||
#include "rpg/cutscene/item/cutsceneitembase.h"
|
||||
|
||||
/**
|
||||
* Updates an idle item. Never completes on its own - the cutscene blocks
|
||||
@@ -24,3 +21,6 @@ bool_t cutsceneIdleUpdate(
|
||||
const cutsceneitem_t *item,
|
||||
cutsceneitemdata_t *data
|
||||
);
|
||||
|
||||
// IDLE has no fields of its own to parse - see cutsceneItemLoadNoop
|
||||
// (cutsceneitembase.h), used directly as its .load callback.
|
||||
|
||||
@@ -19,3 +19,18 @@ bool_t cutsceneMarkerUpdate(
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
errorret_t cutsceneMarkerLoad(
|
||||
yyjson_val *itemObj,
|
||||
cutsceneitem_t *item,
|
||||
uint8_t *pool,
|
||||
size_t *poolOffset
|
||||
) {
|
||||
const char_t *name = yyjson_get_str(yyjson_obj_get(itemObj, "name"));
|
||||
if(name == NULL) {
|
||||
errorThrow("Cutscene item (MARKER): missing 'name'");
|
||||
}
|
||||
item->marker.name = name;
|
||||
|
||||
errorOk();
|
||||
}
|
||||
|
||||
@@ -6,10 +6,7 @@
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "dusk.h"
|
||||
|
||||
typedef struct cutsceneitem_s cutsceneitem_t;
|
||||
typedef union cutsceneitemdata_u cutsceneitemdata_t;
|
||||
#include "rpg/cutscene/item/cutsceneitembase.h"
|
||||
|
||||
typedef struct {
|
||||
const char_t *name;
|
||||
@@ -38,3 +35,19 @@ bool_t cutsceneMarkerUpdate(
|
||||
const cutsceneitem_t *item,
|
||||
cutsceneitemdata_t *data
|
||||
);
|
||||
|
||||
/**
|
||||
* Parses a MARKER cutscene item's JSON fields into item.
|
||||
*
|
||||
* @param itemObj The item's JSON object.
|
||||
* @param item Destination item, already zeroed by the caller.
|
||||
* @param pool Unused (MARKER needs no pool storage).
|
||||
* @param poolOffset Unused (MARKER needs no pool storage).
|
||||
* @return Error code indicating success or failure of the parse.
|
||||
*/
|
||||
errorret_t cutsceneMarkerLoad(
|
||||
yyjson_val *itemObj,
|
||||
cutsceneitem_t *item,
|
||||
uint8_t *pool,
|
||||
size_t *poolOffset
|
||||
);
|
||||
|
||||
@@ -6,10 +6,7 @@
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "dusk.h"
|
||||
|
||||
typedef struct cutsceneitem_s cutsceneitem_t;
|
||||
typedef union cutsceneitemdata_u cutsceneitemdata_t;
|
||||
#include "rpg/cutscene/item/cutsceneitembase.h"
|
||||
|
||||
/**
|
||||
* Starts a restart item (restarts the currently running cutscene from
|
||||
@@ -36,3 +33,6 @@ bool_t cutsceneRestartUpdate(
|
||||
const cutsceneitem_t *item,
|
||||
cutsceneitemdata_t *data
|
||||
);
|
||||
|
||||
// RESTART has no fields of its own to parse - see cutsceneItemLoadNoop
|
||||
// (cutsceneitembase.h), used directly as its .load callback.
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#include "rpg/cutscene/item/cutsceneitem.h"
|
||||
#include "scene/scene.h"
|
||||
#include "rpg/cutscene/item/json/cutscenejsonscenetype.h"
|
||||
|
||||
void cutsceneSceneStart(
|
||||
const cutsceneitem_t *item,
|
||||
@@ -21,3 +22,20 @@ bool_t cutsceneSceneUpdate(
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
errorret_t cutsceneSceneLoad(
|
||||
yyjson_val *itemObj,
|
||||
cutsceneitem_t *item,
|
||||
uint8_t *pool,
|
||||
size_t *poolOffset
|
||||
) {
|
||||
scenetype_t sceneValue;
|
||||
if(!cutsceneJsonLookupSceneType(
|
||||
yyjson_get_str(yyjson_obj_get(itemObj, "sceneType")), &sceneValue
|
||||
)) {
|
||||
errorThrow("Cutscene item (SCENE): invalid 'sceneType'");
|
||||
}
|
||||
item->sceneChange.type = sceneValue;
|
||||
|
||||
errorOk();
|
||||
}
|
||||
|
||||
@@ -6,12 +6,9 @@
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "dusk.h"
|
||||
#include "rpg/cutscene/item/cutsceneitembase.h"
|
||||
#include "scene/scenetype.h"
|
||||
|
||||
typedef struct cutsceneitem_s cutsceneitem_t;
|
||||
typedef union cutsceneitemdata_u cutsceneitemdata_t;
|
||||
|
||||
typedef struct {
|
||||
scenetype_t type;
|
||||
} cutscenescene_t;
|
||||
@@ -42,3 +39,19 @@ bool_t cutsceneSceneUpdate(
|
||||
const cutsceneitem_t *item,
|
||||
cutsceneitemdata_t *data
|
||||
);
|
||||
|
||||
/**
|
||||
* Parses a SCENE cutscene item's JSON fields into item.
|
||||
*
|
||||
* @param itemObj The item's JSON object.
|
||||
* @param item Destination item, already zeroed by the caller.
|
||||
* @param pool Unused (SCENE needs no pool storage).
|
||||
* @param poolOffset Unused (SCENE needs no pool storage).
|
||||
* @return Error code indicating success or failure of the parse.
|
||||
*/
|
||||
errorret_t cutsceneSceneLoad(
|
||||
yyjson_val *itemObj,
|
||||
cutsceneitem_t *item,
|
||||
uint8_t *pool,
|
||||
size_t *poolOffset
|
||||
);
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#include "rpg/cutscene/item/cutsceneitem.h"
|
||||
#include "rpg/cutscene/cutscenesystem.h"
|
||||
#include "rpg/cutscene/item/json/cutscenejsonpauseflags.h"
|
||||
|
||||
void cutsceneSetPauseStart(
|
||||
const cutsceneitem_t *item,
|
||||
@@ -21,3 +22,22 @@ bool_t cutsceneSetPauseUpdate(
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
errorret_t cutsceneSetPauseLoad(
|
||||
yyjson_val *itemObj,
|
||||
cutsceneitem_t *item,
|
||||
uint8_t *pool,
|
||||
size_t *poolOffset
|
||||
) {
|
||||
yyjson_val *flags = yyjson_obj_get(itemObj, "flags");
|
||||
cutscenepause_t value;
|
||||
if(!cutsceneJsonParsePauseFlags(flags, &value)) {
|
||||
errorThrow(
|
||||
"Cutscene item (SET_PAUSE): 'flags' must be an array of valid pause "
|
||||
"flags"
|
||||
);
|
||||
}
|
||||
item->setPause = value;
|
||||
|
||||
errorOk();
|
||||
}
|
||||
|
||||
@@ -7,9 +7,7 @@
|
||||
|
||||
#pragma once
|
||||
#include "rpg/cutscene/cutscenepause.h"
|
||||
|
||||
typedef struct cutsceneitem_s cutsceneitem_t;
|
||||
typedef union cutsceneitemdata_u cutsceneitemdata_t;
|
||||
#include "rpg/cutscene/item/cutsceneitembase.h"
|
||||
|
||||
/**
|
||||
* Starts a set-pause item (applies the new pause flags immediately).
|
||||
@@ -33,3 +31,19 @@ bool_t cutsceneSetPauseUpdate(
|
||||
const cutsceneitem_t *item,
|
||||
cutsceneitemdata_t *data
|
||||
);
|
||||
|
||||
/**
|
||||
* Parses a SET_PAUSE cutscene item's JSON fields into item.
|
||||
*
|
||||
* @param itemObj The item's JSON object.
|
||||
* @param item Destination item, already zeroed by the caller.
|
||||
* @param pool Unused (SET_PAUSE needs no pool storage).
|
||||
* @param poolOffset Unused (SET_PAUSE needs no pool storage).
|
||||
* @return Error code indicating success or failure of the parse.
|
||||
*/
|
||||
errorret_t cutsceneSetPauseLoad(
|
||||
yyjson_val *itemObj,
|
||||
cutsceneitem_t *item,
|
||||
uint8_t *pool,
|
||||
size_t *poolOffset
|
||||
);
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
*/
|
||||
|
||||
#include "rpg/cutscene/item/cutsceneitem.h"
|
||||
#include "rpg/cutscene/item/json/cutscenejsonfield.h"
|
||||
#include "time/time.h"
|
||||
|
||||
void cutsceneWaitStart(
|
||||
@@ -22,3 +23,14 @@ bool_t cutsceneWaitUpdate(
|
||||
data->wait -= TIME.delta;
|
||||
return data->wait <= 0;
|
||||
}
|
||||
|
||||
errorret_t cutsceneWaitLoad(
|
||||
yyjson_val *itemObj,
|
||||
cutsceneitem_t *item,
|
||||
uint8_t *pool,
|
||||
size_t *poolOffset
|
||||
) {
|
||||
item->wait = cutsceneJsonGetFloat(itemObj, "seconds", 0.0f);
|
||||
|
||||
errorOk();
|
||||
}
|
||||
|
||||
@@ -6,10 +6,7 @@
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "dusk.h"
|
||||
|
||||
typedef struct cutsceneitem_s cutsceneitem_t;
|
||||
typedef union cutsceneitemdata_u cutsceneitemdata_t;
|
||||
#include "rpg/cutscene/item/cutsceneitembase.h"
|
||||
|
||||
typedef float_t cutscenewait_t;
|
||||
typedef float_t cutscenewaitdata_t;
|
||||
@@ -35,4 +32,20 @@ void cutsceneWaitStart(
|
||||
bool_t cutsceneWaitUpdate(
|
||||
const cutsceneitem_t *item,
|
||||
cutsceneitemdata_t *data
|
||||
);
|
||||
|
||||
/**
|
||||
* Parses a WAIT cutscene item's JSON fields into item.
|
||||
*
|
||||
* @param itemObj The item's JSON object.
|
||||
* @param item Destination item, already zeroed by the caller.
|
||||
* @param pool Unused (WAIT needs no pool storage).
|
||||
* @param poolOffset Unused (WAIT needs no pool storage).
|
||||
* @return Error code indicating success or failure of the parse.
|
||||
*/
|
||||
errorret_t cutsceneWaitLoad(
|
||||
yyjson_val *itemObj,
|
||||
cutsceneitem_t *item,
|
||||
uint8_t *pool,
|
||||
size_t *poolOffset
|
||||
);
|
||||
@@ -6,10 +6,7 @@
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "dusk.h"
|
||||
|
||||
typedef struct cutsceneitem_s cutsceneitem_t;
|
||||
typedef union cutsceneitemdata_u cutsceneitemdata_t;
|
||||
#include "rpg/cutscene/item/cutsceneitembase.h"
|
||||
|
||||
typedef void (*cutscenecallback_t)(void *userData);
|
||||
|
||||
|
||||
@@ -6,23 +6,34 @@
|
||||
*/
|
||||
|
||||
#include "rpg/cutscene/cutscenesystem.h"
|
||||
#include "rpg/cutscene/item/cutsceneitembase.h"
|
||||
#include "asset/asset.h"
|
||||
#include "asset/assetfile.h"
|
||||
#include "asset/loader/assetloader.h"
|
||||
#include "util/string.h"
|
||||
|
||||
cutsceneitemcallbacks_t CUTSCENE_ITEM_CALLBACKS[CUTSCENE_ITEM_TYPE_COUNT] = {
|
||||
[CUTSCENE_ITEM_TYPE_NULL] = { 0 },
|
||||
|
||||
[CUTSCENE_ITEM_TYPE_TEXT] = {
|
||||
.init = cutsceneTextStart,
|
||||
.update = cutsceneTextUpdate
|
||||
.update = cutsceneTextUpdate,
|
||||
.jsonName = "TEXT",
|
||||
.load = cutsceneTextLoad
|
||||
},
|
||||
|
||||
[CUTSCENE_ITEM_TYPE_TEXT_MINI] = {
|
||||
.init = cutsceneTextMiniStart,
|
||||
.update = cutsceneTextMiniUpdate
|
||||
.update = cutsceneTextMiniUpdate,
|
||||
.jsonName = "TEXT_MINI",
|
||||
.load = cutsceneTextMiniLoad
|
||||
},
|
||||
|
||||
[CUTSCENE_ITEM_TYPE_TEXT_MINI_HIDE] = {
|
||||
.init = cutsceneTextMiniHideStart,
|
||||
.update = cutsceneTextMiniHideUpdate
|
||||
.update = cutsceneTextMiniHideUpdate,
|
||||
.jsonName = "TEXT_MINI_HIDE",
|
||||
.load = cutsceneTextMiniHideLoad
|
||||
},
|
||||
|
||||
[CUTSCENE_ITEM_TYPE_CALLBACK] = {
|
||||
@@ -32,32 +43,45 @@ cutsceneitemcallbacks_t CUTSCENE_ITEM_CALLBACKS[CUTSCENE_ITEM_TYPE_COUNT] = {
|
||||
|
||||
[CUTSCENE_ITEM_TYPE_WAIT] = {
|
||||
.init = cutsceneWaitStart,
|
||||
.update = cutsceneWaitUpdate
|
||||
.update = cutsceneWaitUpdate,
|
||||
.jsonName = "WAIT",
|
||||
.load = cutsceneWaitLoad
|
||||
},
|
||||
|
||||
[CUTSCENE_ITEM_TYPE_CUTSCENE] = {
|
||||
.init = cutsceneCutsceneStart,
|
||||
.update = cutsceneCutsceneUpdate
|
||||
.update = cutsceneCutsceneUpdate,
|
||||
.jsonName = "CUTSCENE",
|
||||
.load = cutsceneCutsceneLoad
|
||||
},
|
||||
|
||||
[CUTSCENE_ITEM_TYPE_ENTITY_TELEPORT] = {
|
||||
.init = cutsceneEntityTeleportStart,
|
||||
.update = cutsceneEntityTeleportUpdate
|
||||
.update = cutsceneEntityTeleportUpdate,
|
||||
.jsonName = "ENTITY_TELEPORT",
|
||||
.load = cutsceneEntityTeleportLoad
|
||||
},
|
||||
|
||||
[CUTSCENE_ITEM_TYPE_ENTITY_WALK_TO] = {
|
||||
.init = cutsceneEntityWalkToStart,
|
||||
.update = cutsceneEntityWalkToUpdate
|
||||
.update = cutsceneEntityWalkToUpdate,
|
||||
.jsonName = "ENTITY_WALK_TO",
|
||||
.load = cutsceneEntityWalkToLoad,
|
||||
.poolSize = cutsceneEntityWalkToPoolSize
|
||||
},
|
||||
|
||||
[CUTSCENE_ITEM_TYPE_FADE] = {
|
||||
.init = cutsceneFadeStart,
|
||||
.update = cutsceneFadeUpdate
|
||||
.update = cutsceneFadeUpdate,
|
||||
.jsonName = "FADE",
|
||||
.load = cutsceneFadeLoad
|
||||
},
|
||||
|
||||
[CUTSCENE_ITEM_TYPE_SET_PAUSE] = {
|
||||
.init = cutsceneSetPauseStart,
|
||||
.update = cutsceneSetPauseUpdate
|
||||
.update = cutsceneSetPauseUpdate,
|
||||
.jsonName = "SET_PAUSE",
|
||||
.load = cutsceneSetPauseLoad
|
||||
},
|
||||
|
||||
[CUTSCENE_ITEM_TYPE_CONCURRENT] = {
|
||||
@@ -67,27 +91,37 @@ cutsceneitemcallbacks_t CUTSCENE_ITEM_CALLBACKS[CUTSCENE_ITEM_TYPE_COUNT] = {
|
||||
|
||||
[CUTSCENE_ITEM_TYPE_ITEM_GIVE] = {
|
||||
.init = cutsceneItemGiveStart,
|
||||
.update = cutsceneItemGiveUpdate
|
||||
.update = cutsceneItemGiveUpdate,
|
||||
.jsonName = "ITEM_GIVE",
|
||||
.load = cutsceneItemGiveLoad
|
||||
},
|
||||
|
||||
[CUTSCENE_ITEM_TYPE_ENTITY_REMOVE] = {
|
||||
.init = cutsceneEntityRemoveStart,
|
||||
.update = cutsceneEntityRemoveUpdate
|
||||
.update = cutsceneEntityRemoveUpdate,
|
||||
.jsonName = "ENTITY_REMOVE",
|
||||
.load = cutsceneEntityRemoveLoad
|
||||
},
|
||||
|
||||
[CUTSCENE_ITEM_TYPE_ENTITY_ADD] = {
|
||||
.init = cutsceneEntityAddStart,
|
||||
.update = cutsceneEntityAddUpdate
|
||||
.update = cutsceneEntityAddUpdate,
|
||||
.jsonName = "ENTITY_ADD",
|
||||
.load = cutsceneEntityAddLoad
|
||||
},
|
||||
|
||||
[CUTSCENE_ITEM_TYPE_ENTITY_TURN] = {
|
||||
.init = cutsceneEntityTurnStart,
|
||||
.update = cutsceneEntityTurnUpdate
|
||||
.update = cutsceneEntityTurnUpdate,
|
||||
.jsonName = "ENTITY_TURN",
|
||||
.load = cutsceneEntityTurnLoad
|
||||
},
|
||||
|
||||
[CUTSCENE_ITEM_TYPE_ENTITY_WALK_TO_ENTITY] = {
|
||||
.init = cutsceneEntityWalkToEntityStart,
|
||||
.update = cutsceneEntityWalkToEntityUpdate
|
||||
.update = cutsceneEntityWalkToEntityUpdate,
|
||||
.jsonName = "ENTITY_WALK_TO_ENTITY",
|
||||
.load = cutsceneEntityWalkToEntityLoad
|
||||
},
|
||||
|
||||
[CUTSCENE_ITEM_TYPE_MAP_AREA_ADD] = {
|
||||
@@ -97,81 +131,114 @@ cutsceneitemcallbacks_t CUTSCENE_ITEM_CALLBACKS[CUTSCENE_ITEM_TYPE_COUNT] = {
|
||||
|
||||
[CUTSCENE_ITEM_TYPE_MAP_AREA_REMOVE] = {
|
||||
.init = cutsceneMapAreaRemoveStart,
|
||||
.update = cutsceneMapAreaRemoveUpdate
|
||||
.update = cutsceneMapAreaRemoveUpdate,
|
||||
.jsonName = "MAP_AREA_REMOVE",
|
||||
.load = cutsceneMapAreaRemoveLoad
|
||||
},
|
||||
|
||||
[CUTSCENE_ITEM_TYPE_MAP_AREA_WAIT] = {
|
||||
.init = cutsceneMapAreaWaitStart,
|
||||
.update = cutsceneMapAreaWaitUpdate
|
||||
.update = cutsceneMapAreaWaitUpdate,
|
||||
.jsonName = "MAP_AREA_WAIT",
|
||||
.load = cutsceneMapAreaWaitLoad,
|
||||
.poolSize = cutsceneMapAreaWaitPoolSize
|
||||
},
|
||||
|
||||
[CUTSCENE_ITEM_TYPE_START_BATTLE] = {
|
||||
.init = cutsceneStartBattleStart,
|
||||
.update = cutsceneStartBattleUpdate
|
||||
.update = cutsceneStartBattleUpdate,
|
||||
.jsonName = "START_BATTLE",
|
||||
.load = cutsceneStartBattleLoad
|
||||
},
|
||||
|
||||
[CUTSCENE_ITEM_TYPE_EMOJI] = {
|
||||
.init = cutsceneEmojiStart,
|
||||
.update = cutsceneEmojiUpdate
|
||||
.update = cutsceneEmojiUpdate,
|
||||
.jsonName = "EMOJI",
|
||||
.load = cutsceneEmojiLoad
|
||||
},
|
||||
|
||||
[CUTSCENE_ITEM_TYPE_SHAKE] = {
|
||||
.init = cutsceneShakeStart,
|
||||
.update = cutsceneShakeUpdate
|
||||
.update = cutsceneShakeUpdate,
|
||||
.jsonName = "SHAKE",
|
||||
.load = cutsceneShakeLoad
|
||||
},
|
||||
|
||||
[CUTSCENE_ITEM_TYPE_BATTLE_WAIT_STATE] = {
|
||||
.update = cutsceneBattleWaitStateUpdate
|
||||
.update = cutsceneBattleWaitStateUpdate,
|
||||
.jsonName = "BATTLE_WAIT_STATE",
|
||||
.load = cutsceneBattleWaitStateLoad
|
||||
},
|
||||
|
||||
[CUTSCENE_ITEM_TYPE_BATTLE_FORCE_ACTION] = {
|
||||
.init = cutsceneBattleForceActionStart,
|
||||
.update = cutsceneBattleForceActionUpdate
|
||||
.update = cutsceneBattleForceActionUpdate,
|
||||
.jsonName = "BATTLE_FORCE_ACTION",
|
||||
.load = cutsceneBattleForceActionLoad
|
||||
},
|
||||
|
||||
[CUTSCENE_ITEM_TYPE_MODAL] = {
|
||||
.init = cutsceneModalStart,
|
||||
.update = cutsceneModalUpdate
|
||||
.update = cutsceneModalUpdate,
|
||||
.jsonName = "MODAL",
|
||||
.load = cutsceneModalLoad
|
||||
},
|
||||
|
||||
[CUTSCENE_ITEM_TYPE_MODAL_OPTIONS_MARKERS] = {
|
||||
.init = cutsceneModalOptionsMarkersStart,
|
||||
.update = cutsceneModalOptionsMarkersUpdate
|
||||
.update = cutsceneModalOptionsMarkersUpdate,
|
||||
.jsonName = "MODAL_OPTIONS_MARKERS",
|
||||
.load = cutsceneModalOptionsMarkersLoad
|
||||
},
|
||||
|
||||
[CUTSCENE_ITEM_TYPE_MODAL_CLOSE] = {
|
||||
.init = cutsceneModalCloseStart,
|
||||
.update = cutsceneModalCloseUpdate
|
||||
.update = cutsceneModalCloseUpdate,
|
||||
.jsonName = "MODAL_CLOSE",
|
||||
.load = cutsceneItemLoadNoop
|
||||
},
|
||||
|
||||
[CUTSCENE_ITEM_TYPE_PRINT] = {
|
||||
.init = cutscenePrintStart,
|
||||
.update = cutscenePrintUpdate
|
||||
.update = cutscenePrintUpdate,
|
||||
.jsonName = "PRINT",
|
||||
.load = cutscenePrintLoad
|
||||
},
|
||||
|
||||
[CUTSCENE_ITEM_TYPE_MARKER] = {
|
||||
.init = cutsceneMarkerStart,
|
||||
.update = cutsceneMarkerUpdate
|
||||
.update = cutsceneMarkerUpdate,
|
||||
.jsonName = "MARKER",
|
||||
.load = cutsceneMarkerLoad
|
||||
},
|
||||
|
||||
[CUTSCENE_ITEM_TYPE_RESTART] = {
|
||||
.init = cutsceneRestartStart,
|
||||
.update = cutsceneRestartUpdate
|
||||
.update = cutsceneRestartUpdate,
|
||||
.jsonName = "RESTART",
|
||||
.load = cutsceneItemLoadNoop
|
||||
},
|
||||
|
||||
[CUTSCENE_ITEM_TYPE_SCENE] = {
|
||||
.init = cutsceneSceneStart,
|
||||
.update = cutsceneSceneUpdate
|
||||
.update = cutsceneSceneUpdate,
|
||||
.jsonName = "SCENE",
|
||||
.load = cutsceneSceneLoad
|
||||
},
|
||||
|
||||
[CUTSCENE_ITEM_TYPE_SAVE_DEVICE_CHECK] = {
|
||||
.init = cutsceneSaveDeviceCheckStart,
|
||||
.update = cutsceneSaveDeviceCheckUpdate
|
||||
.update = cutsceneSaveDeviceCheckUpdate,
|
||||
.jsonName = "SAVE_DEVICE_CHECK",
|
||||
.load = cutsceneSaveDeviceCheckLoad
|
||||
},
|
||||
|
||||
[CUTSCENE_ITEM_TYPE_SAVE_LOAD_ALL_SLOTS] = {
|
||||
.init = cutsceneSaveLoadAllSlotsStart,
|
||||
.update = cutsceneSaveLoadAllSlotsUpdate
|
||||
.update = cutsceneSaveLoadAllSlotsUpdate,
|
||||
.jsonName = "SAVE_LOAD_ALL_SLOTS",
|
||||
.load = cutsceneSaveLoadAllSlotsLoad
|
||||
},
|
||||
|
||||
[CUTSCENE_ITEM_TYPE_KEYBOARD] = {
|
||||
@@ -181,58 +248,95 @@ cutsceneitemcallbacks_t CUTSCENE_ITEM_CALLBACKS[CUTSCENE_ITEM_TYPE_COUNT] = {
|
||||
|
||||
[CUTSCENE_ITEM_TYPE_AUDIO_PLAY] = {
|
||||
.init = cutsceneAudioPlayStart,
|
||||
.update = cutsceneAudioPlayUpdate
|
||||
.update = cutsceneAudioPlayUpdate,
|
||||
.jsonName = "AUDIO_PLAY",
|
||||
.load = cutsceneAudioPlayLoad
|
||||
},
|
||||
|
||||
[CUTSCENE_ITEM_TYPE_AUDIO_STOP] = {
|
||||
.init = cutsceneAudioStopStart,
|
||||
.update = cutsceneAudioStopUpdate
|
||||
.update = cutsceneAudioStopUpdate,
|
||||
.jsonName = "AUDIO_STOP",
|
||||
.load = cutsceneAudioStopLoad
|
||||
},
|
||||
|
||||
[CUTSCENE_ITEM_TYPE_AUDIO_PAUSE] = {
|
||||
.init = cutsceneAudioPauseStart,
|
||||
.update = cutsceneAudioPauseUpdate
|
||||
.update = cutsceneAudioPauseUpdate,
|
||||
.jsonName = "AUDIO_PAUSE",
|
||||
.load = cutsceneAudioPauseLoad
|
||||
},
|
||||
|
||||
[CUTSCENE_ITEM_TYPE_AUDIO_RESUME] = {
|
||||
.init = cutsceneAudioResumeStart,
|
||||
.update = cutsceneAudioResumeUpdate
|
||||
.update = cutsceneAudioResumeUpdate,
|
||||
.jsonName = "AUDIO_RESUME",
|
||||
.load = cutsceneAudioResumeLoad
|
||||
},
|
||||
|
||||
[CUTSCENE_ITEM_TYPE_AUDIO_FADE] = {
|
||||
.init = cutsceneAudioFadeStart,
|
||||
.update = cutsceneAudioFadeUpdate
|
||||
.update = cutsceneAudioFadeUpdate,
|
||||
.jsonName = "AUDIO_FADE",
|
||||
.load = cutsceneAudioFadeLoad
|
||||
},
|
||||
|
||||
[CUTSCENE_ITEM_TYPE_AUDIO_FADE_WAIT] = {
|
||||
.update = cutsceneAudioFadeWaitUpdate
|
||||
.update = cutsceneAudioFadeWaitUpdate,
|
||||
.jsonName = "AUDIO_FADE_WAIT",
|
||||
.load = cutsceneAudioFadeWaitLoad
|
||||
},
|
||||
|
||||
[CUTSCENE_ITEM_TYPE_AUDIO_SET_PAN] = {
|
||||
.init = cutsceneAudioSetPanStart,
|
||||
.update = cutsceneAudioSetPanUpdate
|
||||
.update = cutsceneAudioSetPanUpdate,
|
||||
.jsonName = "AUDIO_SET_PAN",
|
||||
.load = cutsceneAudioSetPanLoad
|
||||
},
|
||||
|
||||
[CUTSCENE_ITEM_TYPE_AUDIO_SET_LOOP] = {
|
||||
.init = cutsceneAudioSetLoopStart,
|
||||
.update = cutsceneAudioSetLoopUpdate
|
||||
.update = cutsceneAudioSetLoopUpdate,
|
||||
.jsonName = "AUDIO_SET_LOOP",
|
||||
.load = cutsceneAudioSetLoopLoad
|
||||
},
|
||||
|
||||
[CUTSCENE_ITEM_TYPE_AUDIO_SET] = {
|
||||
.init = cutsceneAudioSetStart,
|
||||
.update = cutsceneAudioSetUpdate
|
||||
.update = cutsceneAudioSetUpdate,
|
||||
.jsonName = "AUDIO_SET",
|
||||
.load = cutsceneAudioSetLoad
|
||||
},
|
||||
|
||||
[CUTSCENE_ITEM_TYPE_IDLE] = {
|
||||
.update = cutsceneIdleUpdate
|
||||
.update = cutsceneIdleUpdate,
|
||||
.jsonName = "IDLE",
|
||||
.load = cutsceneItemLoadNoop
|
||||
},
|
||||
|
||||
[CUTSCENE_ITEM_TYPE_UI_SHOW] = {
|
||||
.init = cutsceneUIShowStart,
|
||||
.update = cutsceneUIShowUpdate
|
||||
.update = cutsceneUIShowUpdate,
|
||||
.jsonName = "UI_SHOW",
|
||||
.load = cutsceneUIShowLoad
|
||||
}
|
||||
};
|
||||
|
||||
bool_t cutsceneItemLookupType(
|
||||
const char_t *name,
|
||||
cutsceneitemtype_t *outType
|
||||
) {
|
||||
if(name == NULL) return false;
|
||||
for(size_t i = 0; i < CUTSCENE_ITEM_TYPE_COUNT; i++) {
|
||||
const char_t *jsonName = CUTSCENE_ITEM_CALLBACKS[i].jsonName;
|
||||
if(jsonName != NULL && stringEquals(jsonName, name)) {
|
||||
*outType = (cutsceneitemtype_t)i;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void cutsceneItemStart(const cutsceneitem_t *item, cutsceneitemdata_t *data) {
|
||||
cutsceneiteminitcallback_t *init = CUTSCENE_ITEM_CALLBACKS[item->type].init;
|
||||
if(init != NULL) init(item, data);
|
||||
@@ -262,3 +366,35 @@ bool_t cutsceneCutsceneUpdate(
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
errorret_t cutsceneCutsceneLoad(
|
||||
yyjson_val *itemObj,
|
||||
cutsceneitem_t *item,
|
||||
uint8_t *pool,
|
||||
size_t *poolOffset
|
||||
) {
|
||||
const char_t *name = yyjson_get_str(yyjson_obj_get(itemObj, "name"));
|
||||
if(name == NULL) {
|
||||
errorThrow("Cutscene item (CUTSCENE): missing 'name'");
|
||||
}
|
||||
|
||||
// Referenced cutscene is a sibling asset (assets/cutscenes/<name>.jsonc),
|
||||
// resolved to a stable pointer right now rather than deferred to
|
||||
// runtime - assetRequireLoaded re-enters assetUpdate() safely from
|
||||
// within this sync load (see its ASSET_ENTRY_STATE_LOADING_SYNC case),
|
||||
// and the entry is locked forever (never unlocked) so the pointer
|
||||
// stays valid for the process lifetime, same convention as
|
||||
// ui/screen/mainmenu/uimainmenu.c's MAIN_MENU_CUTSCENE_ENTRY.
|
||||
char_t path[ASSET_FILE_NAME_MAX];
|
||||
int32_t pathLen = stringFormat(NULL, 0, "cutscenes/%s.jsonc", name);
|
||||
if(pathLen < 0 || (size_t)pathLen >= ASSET_FILE_NAME_MAX) {
|
||||
errorThrow("Cutscene item (CUTSCENE): 'name' too long");
|
||||
}
|
||||
stringFormat(path, sizeof(path), "cutscenes/%s.jsonc", name);
|
||||
|
||||
assetentry_t *refEntry = assetLock(path, ASSET_LOADER_TYPE_CUTSCENE, NULL);
|
||||
errorChain(assetRequireLoaded(refEntry));
|
||||
item->cutscene = &refEntry->data.cutscene.cutscene;
|
||||
|
||||
errorOk();
|
||||
}
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "error/error.h"
|
||||
#include "yyjson.h"
|
||||
#include "cutscenecallback.h"
|
||||
#include "cutsceneprint.h"
|
||||
#include "control/cutscenewait.h"
|
||||
@@ -170,9 +172,24 @@ typedef bool_t (cutsceneitemupdatecallback_t)(
|
||||
cutsceneitemdata_t *data
|
||||
);
|
||||
|
||||
typedef errorret_t (cutsceneitemloadcallback_t)(
|
||||
yyjson_val *itemObj,
|
||||
cutsceneitem_t *item,
|
||||
uint8_t *pool,
|
||||
size_t *poolOffset
|
||||
);
|
||||
|
||||
// Returns how many pool bytes (see cutsceneJsonPoolAlign) this JSON item
|
||||
// needs - only ENTITY_WALK_TO/MAP_AREA_WAIT need this; every other type's
|
||||
// poolSize is NULL (0 bytes).
|
||||
typedef size_t (cutsceneitempoolsizecallback_t)(yyjson_val *itemObj);
|
||||
|
||||
typedef struct {
|
||||
cutsceneiteminitcallback_t *init;
|
||||
cutsceneitemupdatecallback_t *update;
|
||||
const char_t *jsonName; // NULL if not JSON-authorable
|
||||
cutsceneitemloadcallback_t *load; // NULL if not JSON-authorable
|
||||
cutsceneitempoolsizecallback_t *poolSize; // NULL if this type needs no pool
|
||||
} cutsceneitemcallbacks_t;
|
||||
|
||||
extern cutsceneitemcallbacks_t
|
||||
@@ -201,6 +218,19 @@ bool_t cutsceneItemUpdate(
|
||||
cutsceneitemdata_t *data
|
||||
);
|
||||
|
||||
/**
|
||||
* Looks up name (exact case) against every JSON-authorable item type's
|
||||
* jsonName.
|
||||
*
|
||||
* @param name Name to search for.
|
||||
* @param outType Set to the matching item type on success.
|
||||
* @return true if a matching entry was found, false otherwise.
|
||||
*/
|
||||
bool_t cutsceneItemLookupType(
|
||||
const char_t *name,
|
||||
cutsceneitemtype_t *outType
|
||||
);
|
||||
|
||||
/**
|
||||
* Starts a nested-cutscene item, handing control over to the
|
||||
* referenced cutscene.
|
||||
@@ -226,3 +256,24 @@ bool_t cutsceneCutsceneUpdate(
|
||||
const cutsceneitem_t *item,
|
||||
cutsceneitemdata_t *data
|
||||
);
|
||||
|
||||
/**
|
||||
* Parses a CUTSCENE cutscene item's JSON fields into item. Kept inline here
|
||||
* (rather than its own file) since it's tightly bound to the asset/loader
|
||||
* system itself - it resolves its 'name' to a sibling
|
||||
* assets/cutscenes/<name>.jsonc asset at parse time, mirroring how
|
||||
* cutsceneCutsceneStart/cutsceneCutsceneUpdate stay inline in
|
||||
* cutsceneitem.c rather than getting their own file.
|
||||
*
|
||||
* @param itemObj The item's JSON object.
|
||||
* @param item Destination item, already zeroed by the caller.
|
||||
* @param pool Unused (CUTSCENE needs no pool storage).
|
||||
* @param poolOffset Unused (CUTSCENE needs no pool storage).
|
||||
* @return Error code indicating success or failure of the parse.
|
||||
*/
|
||||
errorret_t cutsceneCutsceneLoad(
|
||||
yyjson_val *itemObj,
|
||||
cutsceneitem_t *item,
|
||||
uint8_t *pool,
|
||||
size_t *poolOffset
|
||||
);
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "cutsceneitembase.h"
|
||||
|
||||
errorret_t cutsceneItemLoadNoop(
|
||||
yyjson_val *itemObj,
|
||||
cutsceneitem_t *item,
|
||||
uint8_t *pool,
|
||||
size_t *poolOffset
|
||||
) {
|
||||
errorOk();
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "dusk.h"
|
||||
#include "error/error.h"
|
||||
#include "yyjson.h"
|
||||
|
||||
typedef struct cutsceneitem_s cutsceneitem_t;
|
||||
typedef union cutsceneitemdata_u cutsceneitemdata_t;
|
||||
|
||||
/**
|
||||
* Shared no-op Load for item types with no JSON fields of their own to
|
||||
* parse (IDLE, RESTART, MODAL_CLOSE) - always succeeds without touching
|
||||
* item.
|
||||
*
|
||||
* @param itemObj The item's JSON object (unused).
|
||||
* @param item Destination item (unused).
|
||||
* @param pool Unused.
|
||||
* @param poolOffset Unused.
|
||||
* @return Always errorOk().
|
||||
*/
|
||||
errorret_t cutsceneItemLoadNoop(
|
||||
yyjson_val *itemObj,
|
||||
cutsceneitem_t *item,
|
||||
uint8_t *pool,
|
||||
size_t *poolOffset
|
||||
);
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#include "cutsceneitem.h"
|
||||
#include "console/console.h"
|
||||
#include "json/cutscenejsonfield.h"
|
||||
|
||||
void cutscenePrintStart(
|
||||
const cutsceneitem_t *item,
|
||||
@@ -21,3 +22,18 @@ bool_t cutscenePrintUpdate(
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
errorret_t cutscenePrintLoad(
|
||||
yyjson_val *itemObj,
|
||||
cutsceneitem_t *item,
|
||||
uint8_t *pool,
|
||||
size_t *poolOffset
|
||||
) {
|
||||
if(!cutsceneJsonCopyString(
|
||||
itemObj, "text", NULL, item->print.text, CUTSCENE_PRINT_MAX_CHARS
|
||||
)) {
|
||||
errorThrow("Cutscene item (PRINT): missing/too-long 'text'");
|
||||
}
|
||||
|
||||
errorOk();
|
||||
}
|
||||
|
||||
@@ -6,10 +6,7 @@
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "dusk.h"
|
||||
|
||||
typedef struct cutsceneitem_s cutsceneitem_t;
|
||||
typedef union cutsceneitemdata_u cutsceneitemdata_t;
|
||||
#include "rpg/cutscene/item/cutsceneitembase.h"
|
||||
|
||||
#define CUTSCENE_PRINT_MAX_CHARS 128
|
||||
|
||||
@@ -39,3 +36,19 @@ bool_t cutscenePrintUpdate(
|
||||
const cutsceneitem_t *item,
|
||||
cutsceneitemdata_t *data
|
||||
);
|
||||
|
||||
/**
|
||||
* Parses a PRINT cutscene item's JSON fields into item.
|
||||
*
|
||||
* @param itemObj The item's JSON object.
|
||||
* @param item Destination item, already zeroed by the caller.
|
||||
* @param pool Unused (PRINT needs no pool storage).
|
||||
* @param poolOffset Unused (PRINT needs no pool storage).
|
||||
* @return Error code indicating success or failure of the parse.
|
||||
*/
|
||||
errorret_t cutscenePrintLoad(
|
||||
yyjson_val *itemObj,
|
||||
cutsceneitem_t *item,
|
||||
uint8_t *pool,
|
||||
size_t *poolOffset
|
||||
);
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
#include "rpg/cutscene/cutscenesystem.h"
|
||||
#include "rpg/entity/entity.h"
|
||||
#include "assert/assert.h"
|
||||
#include "rpg/cutscene/item/json/cutscenejsonentitytype.h"
|
||||
#include "rpg/cutscene/item/json/cutscenejsonfield.h"
|
||||
|
||||
void cutsceneEntityAddStart(
|
||||
const cutsceneitem_t *item,
|
||||
@@ -33,3 +35,25 @@ bool_t cutsceneEntityAddUpdate(
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
errorret_t cutsceneEntityAddLoad(
|
||||
yyjson_val *itemObj,
|
||||
cutsceneitem_t *item,
|
||||
uint8_t *pool,
|
||||
size_t *poolOffset
|
||||
) {
|
||||
entitytype_t entityTypeValue;
|
||||
if(!cutsceneJsonLookupEntityType(
|
||||
yyjson_get_str(yyjson_obj_get(itemObj, "entityType")), &entityTypeValue
|
||||
)) {
|
||||
errorThrow("Cutscene item (ENTITY_ADD): invalid 'entityType'");
|
||||
}
|
||||
item->entityAdd.entityType = entityTypeValue;
|
||||
if(!cutsceneJsonReadWorldPos(
|
||||
yyjson_obj_get(itemObj, "position"), &item->entityAdd.position
|
||||
)) {
|
||||
errorThrow("Cutscene item (ENTITY_ADD): 'position' must be [x, y, z]");
|
||||
}
|
||||
|
||||
errorOk();
|
||||
}
|
||||
|
||||
@@ -8,9 +8,7 @@
|
||||
#pragma once
|
||||
#include "rpg/entity/entitytype.h"
|
||||
#include "rpg/overworld/worldpos.h"
|
||||
|
||||
typedef struct cutsceneitem_s cutsceneitem_t;
|
||||
typedef union cutsceneitemdata_u cutsceneitemdata_t;
|
||||
#include "rpg/cutscene/item/cutsceneitembase.h"
|
||||
|
||||
typedef struct {
|
||||
entitytype_t entityType;
|
||||
@@ -39,3 +37,19 @@ bool_t cutsceneEntityAddUpdate(
|
||||
const cutsceneitem_t *item,
|
||||
cutsceneitemdata_t *data
|
||||
);
|
||||
|
||||
/**
|
||||
* Parses an ENTITY_ADD cutscene item's JSON fields into item.
|
||||
*
|
||||
* @param itemObj The item's JSON object.
|
||||
* @param item Destination item, already zeroed by the caller.
|
||||
* @param pool Unused (ENTITY_ADD needs no pool storage).
|
||||
* @param poolOffset Unused (ENTITY_ADD needs no pool storage).
|
||||
* @return Error code indicating success or failure of the parse.
|
||||
*/
|
||||
errorret_t cutsceneEntityAddLoad(
|
||||
yyjson_val *itemObj,
|
||||
cutsceneitem_t *item,
|
||||
uint8_t *pool,
|
||||
size_t *poolOffset
|
||||
);
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "rpg/cutscene/item/cutsceneitem.h"
|
||||
#include "rpg/cutscene/cutscenesystem.h"
|
||||
#include "rpg/entity/entity.h"
|
||||
#include "rpg/cutscene/item/json/cutscenejsonentityindex.h"
|
||||
|
||||
void cutsceneEntityRemoveStart(
|
||||
const cutsceneitem_t *item,
|
||||
@@ -23,3 +24,18 @@ bool_t cutsceneEntityRemoveUpdate(
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
errorret_t cutsceneEntityRemoveLoad(
|
||||
yyjson_val *itemObj,
|
||||
cutsceneitem_t *item,
|
||||
uint8_t *pool,
|
||||
size_t *poolOffset
|
||||
) {
|
||||
if(!cutsceneJsonGetEntityIndex(
|
||||
yyjson_obj_get(itemObj, "entityIndex"), &item->entityRemove.entityIndex
|
||||
)) {
|
||||
errorThrow("Cutscene item (ENTITY_REMOVE): invalid 'entityIndex'");
|
||||
}
|
||||
|
||||
errorOk();
|
||||
}
|
||||
|
||||
@@ -6,10 +6,7 @@
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "dusk.h"
|
||||
|
||||
typedef struct cutsceneitem_s cutsceneitem_t;
|
||||
typedef union cutsceneitemdata_u cutsceneitemdata_t;
|
||||
#include "rpg/cutscene/item/cutsceneitembase.h"
|
||||
|
||||
typedef struct {
|
||||
uint8_t entityIndex;
|
||||
@@ -37,3 +34,19 @@ bool_t cutsceneEntityRemoveUpdate(
|
||||
const cutsceneitem_t *item,
|
||||
cutsceneitemdata_t *data
|
||||
);
|
||||
|
||||
/**
|
||||
* Parses an ENTITY_REMOVE cutscene item's JSON fields into item.
|
||||
*
|
||||
* @param itemObj The item's JSON object.
|
||||
* @param item Destination item, already zeroed by the caller.
|
||||
* @param pool Unused (ENTITY_REMOVE needs no pool storage).
|
||||
* @param poolOffset Unused (ENTITY_REMOVE needs no pool storage).
|
||||
* @return Error code indicating success or failure of the parse.
|
||||
*/
|
||||
errorret_t cutsceneEntityRemoveLoad(
|
||||
yyjson_val *itemObj,
|
||||
cutsceneitem_t *item,
|
||||
uint8_t *pool,
|
||||
size_t *poolOffset
|
||||
);
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
#include "rpg/cutscene/item/cutsceneitem.h"
|
||||
#include "rpg/cutscene/cutscenesystem.h"
|
||||
#include "rpg/entity/entity.h"
|
||||
#include "rpg/cutscene/item/json/cutscenejsonentityindex.h"
|
||||
#include "rpg/cutscene/item/json/cutscenejsonfield.h"
|
||||
|
||||
void cutsceneEntityTeleportStart(
|
||||
const cutsceneitem_t *item,
|
||||
@@ -25,3 +27,26 @@ bool_t cutsceneEntityTeleportUpdate(
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
errorret_t cutsceneEntityTeleportLoad(
|
||||
yyjson_val *itemObj,
|
||||
cutsceneitem_t *item,
|
||||
uint8_t *pool,
|
||||
size_t *poolOffset
|
||||
) {
|
||||
if(!cutsceneJsonGetEntityIndex(
|
||||
yyjson_obj_get(itemObj, "entityIndex"),
|
||||
&item->entityTeleport.entityIndex
|
||||
)) {
|
||||
errorThrow("Cutscene item (ENTITY_TELEPORT): invalid 'entityIndex'");
|
||||
}
|
||||
if(!cutsceneJsonReadWorldPos(
|
||||
yyjson_obj_get(itemObj, "target"), &item->entityTeleport.target
|
||||
)) {
|
||||
errorThrow(
|
||||
"Cutscene item (ENTITY_TELEPORT): 'target' must be [x, y, z]"
|
||||
);
|
||||
}
|
||||
|
||||
errorOk();
|
||||
}
|
||||
|
||||
@@ -7,9 +7,7 @@
|
||||
|
||||
#pragma once
|
||||
#include "rpg/overworld/worldpos.h"
|
||||
|
||||
typedef struct cutsceneitem_s cutsceneitem_t;
|
||||
typedef union cutsceneitemdata_u cutsceneitemdata_t;
|
||||
#include "rpg/cutscene/item/cutsceneitembase.h"
|
||||
|
||||
typedef struct {
|
||||
uint8_t entityIndex;
|
||||
@@ -38,3 +36,19 @@ bool_t cutsceneEntityTeleportUpdate(
|
||||
const cutsceneitem_t *item,
|
||||
cutsceneitemdata_t *data
|
||||
);
|
||||
|
||||
/**
|
||||
* Parses an ENTITY_TELEPORT cutscene item's JSON fields into item.
|
||||
*
|
||||
* @param itemObj The item's JSON object.
|
||||
* @param item Destination item, already zeroed by the caller.
|
||||
* @param pool Unused (ENTITY_TELEPORT needs no pool storage).
|
||||
* @param poolOffset Unused (ENTITY_TELEPORT needs no pool storage).
|
||||
* @return Error code indicating success or failure of the parse.
|
||||
*/
|
||||
errorret_t cutsceneEntityTeleportLoad(
|
||||
yyjson_val *itemObj,
|
||||
cutsceneitem_t *item,
|
||||
uint8_t *pool,
|
||||
size_t *poolOffset
|
||||
);
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
#include "rpg/cutscene/item/cutsceneitem.h"
|
||||
#include "rpg/cutscene/cutscenesystem.h"
|
||||
#include "rpg/entity/entity.h"
|
||||
#include "rpg/cutscene/item/json/cutscenejsonentityindex.h"
|
||||
#include "rpg/cutscene/item/json/cutscenejsonentitydir.h"
|
||||
|
||||
void cutsceneEntityTurnStart(
|
||||
const cutsceneitem_t *item,
|
||||
@@ -28,3 +30,25 @@ bool_t cutsceneEntityTurnUpdate(
|
||||
entityTurn(entity, item->entityTurn.direction);
|
||||
return false;
|
||||
}
|
||||
|
||||
errorret_t cutsceneEntityTurnLoad(
|
||||
yyjson_val *itemObj,
|
||||
cutsceneitem_t *item,
|
||||
uint8_t *pool,
|
||||
size_t *poolOffset
|
||||
) {
|
||||
if(!cutsceneJsonGetEntityIndex(
|
||||
yyjson_obj_get(itemObj, "entityIndex"), &item->entityTurn.entityIndex
|
||||
)) {
|
||||
errorThrow("Cutscene item (ENTITY_TURN): invalid 'entityIndex'");
|
||||
}
|
||||
entitydir_t dirValue;
|
||||
if(!cutsceneJsonLookupEntityDir(
|
||||
yyjson_get_str(yyjson_obj_get(itemObj, "direction")), &dirValue
|
||||
)) {
|
||||
errorThrow("Cutscene item (ENTITY_TURN): invalid 'direction'");
|
||||
}
|
||||
item->entityTurn.direction = dirValue;
|
||||
|
||||
errorOk();
|
||||
}
|
||||
|
||||
@@ -7,9 +7,7 @@
|
||||
|
||||
#pragma once
|
||||
#include "rpg/entity/entitydir.h"
|
||||
|
||||
typedef struct cutsceneitem_s cutsceneitem_t;
|
||||
typedef union cutsceneitemdata_u cutsceneitemdata_t;
|
||||
#include "rpg/cutscene/item/cutsceneitembase.h"
|
||||
|
||||
typedef struct {
|
||||
uint8_t entityIndex;
|
||||
@@ -40,3 +38,19 @@ bool_t cutsceneEntityTurnUpdate(
|
||||
const cutsceneitem_t *item,
|
||||
cutsceneitemdata_t *data
|
||||
);
|
||||
|
||||
/**
|
||||
* Parses an ENTITY_TURN cutscene item's JSON fields into item.
|
||||
*
|
||||
* @param itemObj The item's JSON object.
|
||||
* @param item Destination item, already zeroed by the caller.
|
||||
* @param pool Unused (ENTITY_TURN needs no pool storage).
|
||||
* @param poolOffset Unused (ENTITY_TURN needs no pool storage).
|
||||
* @return Error code indicating success or failure of the parse.
|
||||
*/
|
||||
errorret_t cutsceneEntityTurnLoad(
|
||||
yyjson_val *itemObj,
|
||||
cutsceneitem_t *item,
|
||||
uint8_t *pool,
|
||||
size_t *poolOffset
|
||||
);
|
||||
|
||||
@@ -8,6 +8,9 @@
|
||||
#include "rpg/cutscene/item/cutsceneitem.h"
|
||||
#include "rpg/cutscene/cutscenesystem.h"
|
||||
#include "rpg/entity/entitypathstep.h"
|
||||
#include "rpg/cutscene/item/json/cutscenejsonentityindex.h"
|
||||
#include "rpg/cutscene/item/json/cutscenejsonfield.h"
|
||||
#include "rpg/cutscene/item/json/cutscenejsonpool.h"
|
||||
|
||||
void cutsceneEntityWalkToStart(
|
||||
const cutsceneitem_t *item,
|
||||
@@ -34,3 +37,53 @@ bool_t cutsceneEntityWalkToUpdate(
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
errorret_t cutsceneEntityWalkToLoad(
|
||||
yyjson_val *itemObj,
|
||||
cutsceneitem_t *item,
|
||||
uint8_t *pool,
|
||||
size_t *poolOffset
|
||||
) {
|
||||
if(!cutsceneJsonGetEntityIndex(
|
||||
yyjson_obj_get(itemObj, "entityIndex"), &item->entityWalkTo.entityIndex
|
||||
)) {
|
||||
errorThrow("Cutscene item (ENTITY_WALK_TO): invalid 'entityIndex'");
|
||||
}
|
||||
item->entityWalkTo.walkAround =
|
||||
cutsceneJsonGetBool(itemObj, "walkAround", true);
|
||||
|
||||
yyjson_val *positions = yyjson_obj_get(itemObj, "positions");
|
||||
size_t count = yyjson_arr_size(positions);
|
||||
if(!yyjson_is_arr(positions) || count == 0 || count > UINT8_MAX) {
|
||||
errorThrow(
|
||||
"Cutscene item (ENTITY_WALK_TO): 'positions' must be a non-empty "
|
||||
"array of [x, y, z]"
|
||||
);
|
||||
}
|
||||
|
||||
*poolOffset = cutsceneJsonPoolAlign(*poolOffset);
|
||||
worldpos_t *dest = (worldpos_t *)(pool + *poolOffset);
|
||||
yyjson_arr_iter iter = yyjson_arr_iter_with(positions);
|
||||
yyjson_val *posVal;
|
||||
size_t i = 0;
|
||||
while((posVal = yyjson_arr_iter_next(&iter)) != NULL) {
|
||||
if(!cutsceneJsonReadWorldPos(posVal, &dest[i])) {
|
||||
errorThrow(
|
||||
"Cutscene item (ENTITY_WALK_TO): position %u must be [x, y, z]",
|
||||
(uint32_t)i
|
||||
);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
item->entityWalkTo.positions = dest;
|
||||
item->entityWalkTo.count = (uint8_t)count;
|
||||
*poolOffset += count * sizeof(worldpos_t);
|
||||
|
||||
errorOk();
|
||||
}
|
||||
|
||||
size_t cutsceneEntityWalkToPoolSize(yyjson_val *itemObj) {
|
||||
yyjson_val *positions = yyjson_obj_get(itemObj, "positions");
|
||||
if(!yyjson_is_arr(positions)) return 0;
|
||||
return yyjson_arr_size(positions) * sizeof(worldpos_t);
|
||||
}
|
||||
|
||||
@@ -7,9 +7,7 @@
|
||||
|
||||
#pragma once
|
||||
#include "rpg/overworld/worldpos.h"
|
||||
|
||||
typedef struct cutsceneitem_s cutsceneitem_t;
|
||||
typedef union cutsceneitemdata_u cutsceneitemdata_t;
|
||||
#include "rpg/cutscene/item/cutsceneitembase.h"
|
||||
|
||||
typedef struct {
|
||||
uint8_t entityIndex;
|
||||
@@ -44,3 +42,29 @@ bool_t cutsceneEntityWalkToUpdate(
|
||||
const cutsceneitem_t *item,
|
||||
cutsceneitemdata_t *data
|
||||
);
|
||||
|
||||
/**
|
||||
* Parses an ENTITY_WALK_TO cutscene item's JSON fields into item, writing
|
||||
* its "positions" array into pool at *poolOffset and advancing it.
|
||||
*
|
||||
* @param itemObj The item's JSON object.
|
||||
* @param item Destination item, already zeroed by the caller.
|
||||
* @param pool Base pointer of the entry's pool allocation.
|
||||
* @param poolOffset In/out cursor into pool.
|
||||
* @return Error code indicating success or failure of the parse.
|
||||
*/
|
||||
errorret_t cutsceneEntityWalkToLoad(
|
||||
yyjson_val *itemObj,
|
||||
cutsceneitem_t *item,
|
||||
uint8_t *pool,
|
||||
size_t *poolOffset
|
||||
);
|
||||
|
||||
/**
|
||||
* Computes how many pool bytes this ENTITY_WALK_TO item's "positions"
|
||||
* array will need.
|
||||
*
|
||||
* @param itemObj The item's JSON object.
|
||||
* @return Pool bytes required (0 if "positions" is missing/not an array).
|
||||
*/
|
||||
size_t cutsceneEntityWalkToPoolSize(yyjson_val *itemObj);
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "rpg/entity/entity.h"
|
||||
#include "rpg/entity/entitypathstep.h"
|
||||
#include "rpg/overworld/map.h"
|
||||
#include "rpg/cutscene/item/json/cutscenejsonentityindex.h"
|
||||
|
||||
void cutsceneEntityWalkToEntityStart(
|
||||
const cutsceneitem_t *item,
|
||||
@@ -39,3 +40,28 @@ bool_t cutsceneEntityWalkToEntityUpdate(
|
||||
|
||||
return entityPathStep(entity, dest, true);
|
||||
}
|
||||
|
||||
errorret_t cutsceneEntityWalkToEntityLoad(
|
||||
yyjson_val *itemObj,
|
||||
cutsceneitem_t *item,
|
||||
uint8_t *pool,
|
||||
size_t *poolOffset
|
||||
) {
|
||||
if(!cutsceneJsonGetEntityIndex(
|
||||
yyjson_obj_get(itemObj, "entityIndex"),
|
||||
&item->entityWalkToEntity.entityIndex
|
||||
) || !cutsceneJsonGetEntityIndex(
|
||||
yyjson_obj_get(itemObj, "targetEntityIndex"),
|
||||
&item->entityWalkToEntity.targetEntityIndex
|
||||
)) {
|
||||
errorThrow(
|
||||
"Cutscene item (ENTITY_WALK_TO_ENTITY): invalid entity index"
|
||||
);
|
||||
}
|
||||
item->entityWalkToEntity.offsetX =
|
||||
(worldunit_t)yyjson_get_int(yyjson_obj_get(itemObj, "offsetX"));
|
||||
item->entityWalkToEntity.offsetY =
|
||||
(worldunit_t)yyjson_get_int(yyjson_obj_get(itemObj, "offsetY"));
|
||||
|
||||
errorOk();
|
||||
}
|
||||
|
||||
@@ -7,9 +7,7 @@
|
||||
|
||||
#pragma once
|
||||
#include "rpg/overworld/worldpos.h"
|
||||
|
||||
typedef struct cutsceneitem_s cutsceneitem_t;
|
||||
typedef union cutsceneitemdata_u cutsceneitemdata_t;
|
||||
#include "rpg/cutscene/item/cutsceneitembase.h"
|
||||
|
||||
typedef struct {
|
||||
uint8_t entityIndex;
|
||||
@@ -44,3 +42,19 @@ bool_t cutsceneEntityWalkToEntityUpdate(
|
||||
const cutsceneitem_t *item,
|
||||
cutsceneitemdata_t *data
|
||||
);
|
||||
|
||||
/**
|
||||
* Parses an ENTITY_WALK_TO_ENTITY cutscene item's JSON fields into item.
|
||||
*
|
||||
* @param itemObj The item's JSON object.
|
||||
* @param item Destination item, already zeroed by the caller.
|
||||
* @param pool Unused (ENTITY_WALK_TO_ENTITY needs no pool storage).
|
||||
* @param poolOffset Unused (ENTITY_WALK_TO_ENTITY needs no pool storage).
|
||||
* @return Error code indicating success or failure of the parse.
|
||||
*/
|
||||
errorret_t cutsceneEntityWalkToEntityLoad(
|
||||
yyjson_val *itemObj,
|
||||
cutsceneitem_t *item,
|
||||
uint8_t *pool,
|
||||
size_t *poolOffset
|
||||
);
|
||||
|
||||
@@ -22,3 +22,17 @@ bool_t cutsceneItemGiveUpdate(
|
||||
) {
|
||||
return !uiTextboxMainIsActive();
|
||||
}
|
||||
|
||||
errorret_t cutsceneItemGiveLoad(
|
||||
yyjson_val *itemObj,
|
||||
cutsceneitem_t *item,
|
||||
uint8_t *pool,
|
||||
size_t *poolOffset
|
||||
) {
|
||||
item->itemGive.item =
|
||||
(itemid_t)yyjson_get_int(yyjson_obj_get(itemObj, "item"));
|
||||
item->itemGive.quantity =
|
||||
(uint8_t)yyjson_get_int(yyjson_obj_get(itemObj, "quantity"));
|
||||
|
||||
errorOk();
|
||||
}
|
||||
|
||||
@@ -7,9 +7,7 @@
|
||||
|
||||
#pragma once
|
||||
#include "rpg/item/item.h"
|
||||
|
||||
typedef struct cutsceneitem_s cutsceneitem_t;
|
||||
typedef union cutsceneitemdata_u cutsceneitemdata_t;
|
||||
#include "rpg/cutscene/item/cutsceneitembase.h"
|
||||
|
||||
typedef struct {
|
||||
itemid_t item;
|
||||
@@ -38,3 +36,19 @@ bool_t cutsceneItemGiveUpdate(
|
||||
const cutsceneitem_t *item,
|
||||
cutsceneitemdata_t *data
|
||||
);
|
||||
|
||||
/**
|
||||
* Parses an ITEM_GIVE cutscene item's JSON fields into item.
|
||||
*
|
||||
* @param itemObj The item's JSON object.
|
||||
* @param item Destination item, already zeroed by the caller.
|
||||
* @param pool Unused (ITEM_GIVE needs no pool storage).
|
||||
* @param poolOffset Unused (ITEM_GIVE needs no pool storage).
|
||||
* @return Error code indicating success or failure of the parse.
|
||||
*/
|
||||
errorret_t cutsceneItemGiveLoad(
|
||||
yyjson_val *itemObj,
|
||||
cutsceneitem_t *item,
|
||||
uint8_t *pool,
|
||||
size_t *poolOffset
|
||||
);
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
# 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
|
||||
cutscenejsonenum.c
|
||||
cutscenejsonfield.c
|
||||
cutscenejsonentityindex.c
|
||||
cutscenejsonareaid.c
|
||||
cutscenejsonpool.c
|
||||
cutscenejsonpauseflags.c
|
||||
cutscenejsoneasing.c
|
||||
cutscenejsonemoji.c
|
||||
cutscenejsonentitytype.c
|
||||
cutscenejsonentitydir.c
|
||||
cutscenejsonbattleencounter.c
|
||||
cutscenejsonbattlestate.c
|
||||
cutscenejsonscenetype.c
|
||||
cutscenejsonuiscreentype.c
|
||||
cutscenejsonaudiochannel.c
|
||||
)
|
||||
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "cutscenejsonareaid.h"
|
||||
#include "util/string.h"
|
||||
|
||||
bool_t cutsceneJsonGetAreaId(yyjson_val *val, uint8_t *outAreaId) {
|
||||
if(yyjson_is_str(val)) {
|
||||
const char_t *name = yyjson_get_str(val);
|
||||
if(stringCompareInsensitive(name, "LAST_CREATED") == 0) {
|
||||
*outAreaId = CUTSCENE_JSON_AREA_SENTINEL_LAST_CREATED;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if(!yyjson_is_int(val)) return false;
|
||||
*outAreaId = (uint8_t)yyjson_get_int(val);
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "dusk.h"
|
||||
#include "yyjson.h"
|
||||
|
||||
// Sentinel accepted in place of a literal area id - see cutscenesystem.h's
|
||||
// CUTSCENE_AREA_LAST_CREATED. Kept local since it's a JSON-authoring
|
||||
// convenience, not part of the item struct definitions themselves.
|
||||
#define CUTSCENE_JSON_AREA_SENTINEL_LAST_CREATED ((uint8_t)0xFF)
|
||||
|
||||
/**
|
||||
* Resolves a JSON value that's either the "LAST_CREATED" map area sentinel
|
||||
* string or a plain integer area id.
|
||||
*
|
||||
* @param val JSON value to resolve (a string or a number).
|
||||
* @param outAreaId Set to the resolved area id on success.
|
||||
* @return true if val resolved to a valid area id, false otherwise.
|
||||
*/
|
||||
bool_t cutsceneJsonGetAreaId(yyjson_val *val, uint8_t *outAreaId);
|
||||
@@ -0,0 +1,49 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "cutscenejsonaudiochannel.h"
|
||||
#include "cutscenejsonenum.h"
|
||||
|
||||
static const cutscenejsonenumentry_t CUTSCENE_JSON_AUDIO_CHANNEL_TABLE[] = {
|
||||
{ "BGM_0", AUDIO_MIXER_CHANNEL_BGM_0 },
|
||||
{ "VOICE_0", AUDIO_MIXER_CHANNEL_VOICE_0 },
|
||||
{ "VOICE_1", AUDIO_MIXER_CHANNEL_VOICE_1 },
|
||||
{ "SFX_0", AUDIO_MIXER_CHANNEL_SFX_0 },
|
||||
{ "SFX_1", AUDIO_MIXER_CHANNEL_SFX_1 },
|
||||
{ "SFX_2", AUDIO_MIXER_CHANNEL_SFX_2 },
|
||||
{ "SFX_3", AUDIO_MIXER_CHANNEL_SFX_3 },
|
||||
};
|
||||
#define CUTSCENE_JSON_AUDIO_CHANNEL_TABLE_COUNT \
|
||||
(sizeof(CUTSCENE_JSON_AUDIO_CHANNEL_TABLE) / \
|
||||
sizeof(cutscenejsonenumentry_t))
|
||||
|
||||
bool_t cutsceneJsonLookupAudioChannel(
|
||||
const char_t *name,
|
||||
audiomixerchannel_t *out
|
||||
) {
|
||||
int32_t value;
|
||||
if(!cutsceneJsonLookupEnumInsensitive(
|
||||
CUTSCENE_JSON_AUDIO_CHANNEL_TABLE,
|
||||
CUTSCENE_JSON_AUDIO_CHANNEL_TABLE_COUNT, name, &value
|
||||
)) {
|
||||
return false;
|
||||
}
|
||||
*out = (audiomixerchannel_t)value;
|
||||
return true;
|
||||
}
|
||||
|
||||
errorret_t cutsceneJsonLoadAudioChannelOnly(
|
||||
yyjson_val *itemObj,
|
||||
audiomixerchannel_t *outChannel
|
||||
) {
|
||||
if(!cutsceneJsonLookupAudioChannel(
|
||||
yyjson_get_str(yyjson_obj_get(itemObj, "channel")), outChannel
|
||||
)) {
|
||||
errorThrow("Cutscene item: invalid 'channel'");
|
||||
}
|
||||
errorOk();
|
||||
}
|
||||
@@ -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"
|
||||
#include "error/error.h"
|
||||
#include "yyjson.h"
|
||||
#include "audio/mixer/audiomixerchannel.h"
|
||||
|
||||
/**
|
||||
* Looks up name (case-insensitively) against the audio mixer channel
|
||||
* table.
|
||||
*
|
||||
* @param name Name to search for.
|
||||
* @param out Set to the matching channel on success.
|
||||
* @return true if a matching entry was found, false otherwise.
|
||||
*/
|
||||
bool_t cutsceneJsonLookupAudioChannel(
|
||||
const char_t *name,
|
||||
audiomixerchannel_t *out
|
||||
);
|
||||
|
||||
/**
|
||||
* Reads itemObj's "channel" field via cutsceneJsonLookupAudioChannel,
|
||||
* erroring if missing/invalid - shared by every channel-only item type
|
||||
* (AUDIO_STOP/PAUSE/RESUME/FADE_WAIT), which differ only in which item
|
||||
* union field they store the result in.
|
||||
*
|
||||
* @param itemObj The item's JSON object.
|
||||
* @param outChannel Set to the parsed channel on success.
|
||||
* @return Error code indicating success or failure of the parse.
|
||||
*/
|
||||
errorret_t cutsceneJsonLoadAudioChannelOnly(
|
||||
yyjson_val *itemObj,
|
||||
audiomixerchannel_t *outChannel
|
||||
);
|
||||
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "cutscenejsonbattleencounter.h"
|
||||
#include "cutscenejsonenum.h"
|
||||
|
||||
static const cutscenejsonenumentry_t
|
||||
CUTSCENE_JSON_BATTLE_ENCOUNTER_TABLE[] = {
|
||||
{ "REGULAR", BATTLE_ENCOUNTER_REGULAR },
|
||||
{ "PLAYER_ADVANTAGE", BATTLE_ENCOUNTER_PLAYER_ADVANTAGE },
|
||||
{ "BACK_ATTACK", BATTLE_ENCOUNTER_BACK_ATTACK },
|
||||
};
|
||||
#define CUTSCENE_JSON_BATTLE_ENCOUNTER_TABLE_COUNT \
|
||||
(sizeof(CUTSCENE_JSON_BATTLE_ENCOUNTER_TABLE) / \
|
||||
sizeof(cutscenejsonenumentry_t))
|
||||
|
||||
bool_t cutsceneJsonLookupBattleEncounter(
|
||||
const char_t *name,
|
||||
battleencountertype_t *out
|
||||
) {
|
||||
int32_t value;
|
||||
if(!cutsceneJsonLookupEnumInsensitive(
|
||||
CUTSCENE_JSON_BATTLE_ENCOUNTER_TABLE,
|
||||
CUTSCENE_JSON_BATTLE_ENCOUNTER_TABLE_COUNT, name, &value
|
||||
)) {
|
||||
return false;
|
||||
}
|
||||
*out = (battleencountertype_t)value;
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "dusk.h"
|
||||
#include "rpg/battle/battle.h"
|
||||
|
||||
/**
|
||||
* Looks up name (case-insensitively) against the battle encounter type
|
||||
* table.
|
||||
*
|
||||
* @param name Name to search for.
|
||||
* @param out Set to the matching encounter type on success.
|
||||
* @return true if a matching entry was found, false otherwise.
|
||||
*/
|
||||
bool_t cutsceneJsonLookupBattleEncounter(
|
||||
const char_t *name,
|
||||
battleencountertype_t *out
|
||||
);
|
||||
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "cutscenejsonbattlestate.h"
|
||||
#include "cutscenejsonenum.h"
|
||||
|
||||
static const cutscenejsonenumentry_t CUTSCENE_JSON_BATTLE_STATE_TABLE[] = {
|
||||
{ "NONE", BATTLE_STATE_NONE },
|
||||
{ "OPENING", BATTLE_STATE_OPENING },
|
||||
{ "PRE_ROUND", BATTLE_STATE_PRE_ROUND },
|
||||
{ "PLAYER_SELECTION", BATTLE_STATE_PLAYER_SELECTION },
|
||||
{ "AI_SELECTION", BATTLE_STATE_AI_SELECTION },
|
||||
{ "MOVES_EXECUTING", BATTLE_STATE_MOVES_EXECUTING },
|
||||
{ "POST_ROUND", BATTLE_STATE_POST_ROUND },
|
||||
{ "ENDED", BATTLE_STATE_ENDED },
|
||||
};
|
||||
#define CUTSCENE_JSON_BATTLE_STATE_TABLE_COUNT \
|
||||
(sizeof(CUTSCENE_JSON_BATTLE_STATE_TABLE) / sizeof(cutscenejsonenumentry_t))
|
||||
|
||||
bool_t cutsceneJsonLookupBattleState(const char_t *name, battlestate_t *out) {
|
||||
int32_t value;
|
||||
if(!cutsceneJsonLookupEnumInsensitive(
|
||||
CUTSCENE_JSON_BATTLE_STATE_TABLE, CUTSCENE_JSON_BATTLE_STATE_TABLE_COUNT,
|
||||
name, &value
|
||||
)) {
|
||||
return false;
|
||||
}
|
||||
*out = (battlestate_t)value;
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "dusk.h"
|
||||
#include "rpg/battle/battle.h"
|
||||
|
||||
/**
|
||||
* Looks up name (case-insensitively) against the battle state table.
|
||||
*
|
||||
* @param name Name to search for.
|
||||
* @param out Set to the matching battle state on success.
|
||||
* @return true if a matching entry was found, false otherwise.
|
||||
*/
|
||||
bool_t cutsceneJsonLookupBattleState(const char_t *name, battlestate_t *out);
|
||||
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "cutscenejsoneasing.h"
|
||||
#include "cutscenejsonenum.h"
|
||||
|
||||
static const cutscenejsonenumentry_t CUTSCENE_JSON_EASING_TABLE[] = {
|
||||
{ "LINEAR", EASING_LINEAR },
|
||||
{ "IN_SINE", EASING_IN_SINE },
|
||||
{ "OUT_SINE", EASING_OUT_SINE },
|
||||
{ "IN_OUT_SINE", EASING_IN_OUT_SINE },
|
||||
{ "IN_QUAD", EASING_IN_QUAD },
|
||||
{ "OUT_QUAD", EASING_OUT_QUAD },
|
||||
{ "IN_OUT_QUAD", EASING_IN_OUT_QUAD },
|
||||
{ "IN_CUBIC", EASING_IN_CUBIC },
|
||||
{ "OUT_CUBIC", EASING_OUT_CUBIC },
|
||||
{ "IN_OUT_CUBIC", EASING_IN_OUT_CUBIC },
|
||||
{ "IN_QUART", EASING_IN_QUART },
|
||||
{ "OUT_QUART", EASING_OUT_QUART },
|
||||
{ "IN_OUT_QUART", EASING_IN_OUT_QUART },
|
||||
{ "IN_BACK", EASING_IN_BACK },
|
||||
{ "OUT_BACK", EASING_OUT_BACK },
|
||||
{ "IN_OUT_BACK", EASING_IN_OUT_BACK },
|
||||
};
|
||||
#define CUTSCENE_JSON_EASING_TABLE_COUNT \
|
||||
(sizeof(CUTSCENE_JSON_EASING_TABLE) / sizeof(cutscenejsonenumentry_t))
|
||||
|
||||
bool_t cutsceneJsonLookupEasing(const char_t *name, easingtype_t *out) {
|
||||
int32_t value;
|
||||
if(!cutsceneJsonLookupEnumInsensitive(
|
||||
CUTSCENE_JSON_EASING_TABLE, CUTSCENE_JSON_EASING_TABLE_COUNT, name,
|
||||
&value
|
||||
)) {
|
||||
return false;
|
||||
}
|
||||
*out = (easingtype_t)value;
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "dusk.h"
|
||||
#include "animation/easing.h"
|
||||
|
||||
/**
|
||||
* Looks up name (case-insensitively) against the easing type table.
|
||||
*
|
||||
* @param name Name to search for.
|
||||
* @param out Set to the matching easing type on success.
|
||||
* @return true if a matching entry was found, false otherwise.
|
||||
*/
|
||||
bool_t cutsceneJsonLookupEasing(const char_t *name, easingtype_t *out);
|
||||
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "cutscenejsonemoji.h"
|
||||
#include "cutscenejsonenum.h"
|
||||
|
||||
static const cutscenejsonenumentry_t CUTSCENE_JSON_UI_EMOJI_TABLE[] = {
|
||||
{ "NULL", UI_EMOJI_NULL },
|
||||
{ "QUESTION_MARK", UI_EMOJI_QUESTION_MARK },
|
||||
{ "EXCLAMATION_MARK", UI_EMOJI_EXCLAMATION_MARK },
|
||||
};
|
||||
#define CUTSCENE_JSON_UI_EMOJI_TABLE_COUNT \
|
||||
(sizeof(CUTSCENE_JSON_UI_EMOJI_TABLE) / sizeof(cutscenejsonenumentry_t))
|
||||
|
||||
bool_t cutsceneJsonLookupEmoji(const char_t *name, uiemojitype_t *out) {
|
||||
int32_t value;
|
||||
if(!cutsceneJsonLookupEnumInsensitive(
|
||||
CUTSCENE_JSON_UI_EMOJI_TABLE, CUTSCENE_JSON_UI_EMOJI_TABLE_COUNT, name,
|
||||
&value
|
||||
)) {
|
||||
return false;
|
||||
}
|
||||
*out = (uiemojitype_t)value;
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "dusk.h"
|
||||
#include "ui/rpg/uiemoji.h"
|
||||
|
||||
/**
|
||||
* Looks up name (case-insensitively) against the emoji type table.
|
||||
*
|
||||
* @param name Name to search for.
|
||||
* @param out Set to the matching emoji type on success.
|
||||
* @return true if a matching entry was found, false otherwise.
|
||||
*/
|
||||
bool_t cutsceneJsonLookupEmoji(const char_t *name, uiemojitype_t *out);
|
||||
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "cutscenejsonentitydir.h"
|
||||
#include "cutscenejsonenum.h"
|
||||
|
||||
static const cutscenejsonenumentry_t CUTSCENE_JSON_ENTITY_DIR_TABLE[] = {
|
||||
{ "NORTH", ENTITY_DIR_NORTH },
|
||||
{ "EAST", ENTITY_DIR_EAST },
|
||||
{ "SOUTH", ENTITY_DIR_SOUTH },
|
||||
{ "WEST", ENTITY_DIR_WEST },
|
||||
{ "UP", ENTITY_DIR_UP },
|
||||
{ "RIGHT", ENTITY_DIR_RIGHT },
|
||||
{ "DOWN", ENTITY_DIR_DOWN },
|
||||
{ "LEFT", ENTITY_DIR_LEFT },
|
||||
};
|
||||
#define CUTSCENE_JSON_ENTITY_DIR_TABLE_COUNT \
|
||||
(sizeof(CUTSCENE_JSON_ENTITY_DIR_TABLE) / sizeof(cutscenejsonenumentry_t))
|
||||
|
||||
bool_t cutsceneJsonLookupEntityDir(const char_t *name, entitydir_t *out) {
|
||||
int32_t value;
|
||||
if(!cutsceneJsonLookupEnumInsensitive(
|
||||
CUTSCENE_JSON_ENTITY_DIR_TABLE, CUTSCENE_JSON_ENTITY_DIR_TABLE_COUNT,
|
||||
name, &value
|
||||
)) {
|
||||
return false;
|
||||
}
|
||||
*out = (entitydir_t)value;
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "dusk.h"
|
||||
#include "rpg/entity/entitydir.h"
|
||||
|
||||
/**
|
||||
* Looks up name (case-insensitively) against the entity direction table.
|
||||
*
|
||||
* @param name Name to search for.
|
||||
* @param out Set to the matching direction on success.
|
||||
* @return true if a matching entry was found, false otherwise.
|
||||
*/
|
||||
bool_t cutsceneJsonLookupEntityDir(const char_t *name, entitydir_t *out);
|
||||
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "cutscenejsonentityindex.h"
|
||||
#include "util/string.h"
|
||||
|
||||
bool_t cutsceneJsonGetEntityIndex(yyjson_val *val, uint8_t *outIndex) {
|
||||
if(yyjson_is_str(val)) {
|
||||
const char_t *name = yyjson_get_str(val);
|
||||
if(stringCompareInsensitive(name, "INTERACT") == 0) {
|
||||
*outIndex = CUTSCENE_JSON_ENTITY_SENTINEL_INTERACT;
|
||||
return true;
|
||||
}
|
||||
if(stringCompareInsensitive(name, "INTERACTED") == 0) {
|
||||
*outIndex = CUTSCENE_JSON_ENTITY_SENTINEL_INTERACTED;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if(!yyjson_is_int(val)) return false;
|
||||
*outIndex = (uint8_t)yyjson_get_int(val);
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "dusk.h"
|
||||
#include "yyjson.h"
|
||||
|
||||
// Sentinels accepted in place of a literal entity index - see
|
||||
// cutscenesystem.h's CUTSCENE_ENTITY_INTERACT/INTERACTED. Kept local
|
||||
// since they're a JSON-authoring convenience, not part of the item
|
||||
// struct definitions themselves.
|
||||
#define CUTSCENE_JSON_ENTITY_SENTINEL_INTERACT ((uint8_t)0xFE)
|
||||
#define CUTSCENE_JSON_ENTITY_SENTINEL_INTERACTED ((uint8_t)0xFD)
|
||||
|
||||
/**
|
||||
* Resolves a JSON value that's either an entity index sentinel string
|
||||
* ("INTERACT"/"INTERACTED") or a plain integer entity index.
|
||||
*
|
||||
* @param val JSON value to resolve (a string or a number).
|
||||
* @param outIndex Set to the resolved index on success.
|
||||
* @return true if val resolved to a valid index, false otherwise.
|
||||
*/
|
||||
bool_t cutsceneJsonGetEntityIndex(yyjson_val *val, uint8_t *outIndex);
|
||||
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "cutscenejsonentitytype.h"
|
||||
#include "cutscenejsonenum.h"
|
||||
|
||||
static const cutscenejsonenumentry_t CUTSCENE_JSON_ENTITY_TYPE_TABLE[] = {
|
||||
{ "NULL", ENTITY_TYPE_NULL },
|
||||
{ "PLAYER", ENTITY_TYPE_PLAYER },
|
||||
{ "NPC", ENTITY_TYPE_NPC },
|
||||
{ "ITEM", ENTITY_TYPE_ITEM },
|
||||
};
|
||||
#define CUTSCENE_JSON_ENTITY_TYPE_TABLE_COUNT \
|
||||
(sizeof(CUTSCENE_JSON_ENTITY_TYPE_TABLE) / sizeof(cutscenejsonenumentry_t))
|
||||
|
||||
bool_t cutsceneJsonLookupEntityType(const char_t *name, entitytype_t *out) {
|
||||
int32_t value;
|
||||
if(!cutsceneJsonLookupEnumInsensitive(
|
||||
CUTSCENE_JSON_ENTITY_TYPE_TABLE, CUTSCENE_JSON_ENTITY_TYPE_TABLE_COUNT,
|
||||
name, &value
|
||||
)) {
|
||||
return false;
|
||||
}
|
||||
*out = (entitytype_t)value;
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "dusk.h"
|
||||
#include "rpg/entity/entitytype.h"
|
||||
|
||||
/**
|
||||
* Looks up name (case-insensitively) against the entity type table.
|
||||
*
|
||||
* @param name Name to search for.
|
||||
* @param out Set to the matching entity type on success.
|
||||
* @return true if a matching entry was found, false otherwise.
|
||||
*/
|
||||
bool_t cutsceneJsonLookupEntityType(const char_t *name, entitytype_t *out);
|
||||
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "cutscenejsonenum.h"
|
||||
#include "util/string.h"
|
||||
|
||||
bool_t cutsceneJsonLookupEnum(
|
||||
const cutscenejsonenumentry_t *table,
|
||||
const size_t tableCount,
|
||||
const char_t *name,
|
||||
int32_t *outValue
|
||||
) {
|
||||
if(name == NULL) return false;
|
||||
for(size_t i = 0; i < tableCount; i++) {
|
||||
if(stringEquals(table[i].name, name)) {
|
||||
*outValue = table[i].value;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool_t cutsceneJsonLookupEnumInsensitive(
|
||||
const cutscenejsonenumentry_t *table,
|
||||
const size_t tableCount,
|
||||
const char_t *name,
|
||||
int32_t *outValue
|
||||
) {
|
||||
if(name == NULL) return false;
|
||||
for(size_t i = 0; i < tableCount; i++) {
|
||||
if(stringCompareInsensitive(table[i].name, name) == 0) {
|
||||
*outValue = table[i].value;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* 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 {
|
||||
const char_t *name;
|
||||
int32_t value;
|
||||
} cutscenejsonenumentry_t;
|
||||
|
||||
/**
|
||||
* Looks up name in a {name, value} table via stringEquals - exact case,
|
||||
* used only for the top-level item "type" name (the one enum-ish field
|
||||
* the original tool's ITEM_TYPE dict looked up without .upper()).
|
||||
*
|
||||
* @param table Table to search.
|
||||
* @param tableCount Number of entries in table.
|
||||
* @param name Name to search for.
|
||||
* @param outValue Set to the matching entry's value on success.
|
||||
* @return true if a matching entry was found, false otherwise.
|
||||
*/
|
||||
bool_t cutsceneJsonLookupEnum(
|
||||
const cutscenejsonenumentry_t *table,
|
||||
const size_t tableCount,
|
||||
const char_t *name,
|
||||
int32_t *outValue
|
||||
);
|
||||
|
||||
/**
|
||||
* Looks up name in a {name, value} table via stringCompareInsensitive -
|
||||
* every other enum-ish field (pause flags, entity/scene/battle/audio
|
||||
* enums, ...) is authored case-insensitively, matching the original
|
||||
* tool's ENUM_TABLE[name.upper()] lookups.
|
||||
*
|
||||
* @param table Table to search.
|
||||
* @param tableCount Number of entries in table.
|
||||
* @param name Name to search for.
|
||||
* @param outValue Set to the matching entry's value on success.
|
||||
* @return true if a matching entry was found, false otherwise.
|
||||
*/
|
||||
bool_t cutsceneJsonLookupEnumInsensitive(
|
||||
const cutscenejsonenumentry_t *table,
|
||||
const size_t tableCount,
|
||||
const char_t *name,
|
||||
int32_t *outValue
|
||||
);
|
||||
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "cutscenejsonfield.h"
|
||||
#include "util/string.h"
|
||||
|
||||
bool_t cutsceneJsonCopyString(
|
||||
yyjson_val *obj,
|
||||
const char_t *key,
|
||||
const char_t *defaultValue,
|
||||
char_t *dest,
|
||||
const size_t destCapacity
|
||||
) {
|
||||
yyjson_val *val = yyjson_obj_get(obj, key);
|
||||
const char_t *str = yyjson_get_str(val);
|
||||
size_t len;
|
||||
if(str == NULL) {
|
||||
if(defaultValue == NULL) return false;
|
||||
str = defaultValue;
|
||||
len = (size_t)stringFormat(NULL, 0, "%s", str);
|
||||
} else {
|
||||
len = yyjson_get_len(val);
|
||||
}
|
||||
if(len >= destCapacity) return false;
|
||||
stringCopy(dest, str, destCapacity);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool_t cutsceneJsonReadWorldPos(yyjson_val *arr, worldpos_t *out) {
|
||||
if(!yyjson_is_arr(arr) || yyjson_arr_size(arr) != 3) return false;
|
||||
yyjson_val *x = yyjson_arr_get(arr, 0);
|
||||
yyjson_val *y = yyjson_arr_get(arr, 1);
|
||||
yyjson_val *z = yyjson_arr_get(arr, 2);
|
||||
if(!yyjson_is_int(x) || !yyjson_is_int(y) || !yyjson_is_int(z)) return false;
|
||||
out->x = (worldunit_t)yyjson_get_int(x);
|
||||
out->y = (worldunit_t)yyjson_get_int(y);
|
||||
out->z = (worldunit_t)yyjson_get_int(z);
|
||||
return true;
|
||||
}
|
||||
|
||||
int32_t cutsceneJsonGetInt(
|
||||
yyjson_val *obj,
|
||||
const char_t *key,
|
||||
const int32_t defaultValue
|
||||
) {
|
||||
yyjson_val *val = yyjson_obj_get(obj, key);
|
||||
return val == NULL ? defaultValue : (int32_t)yyjson_get_int(val);
|
||||
}
|
||||
|
||||
float_t cutsceneJsonGetFloat(
|
||||
yyjson_val *obj,
|
||||
const char_t *key,
|
||||
const float_t defaultValue
|
||||
) {
|
||||
yyjson_val *val = yyjson_obj_get(obj, key);
|
||||
return val == NULL ? defaultValue : (float_t)yyjson_get_num(val);
|
||||
}
|
||||
|
||||
bool_t cutsceneJsonGetBool(
|
||||
yyjson_val *obj,
|
||||
const char_t *key,
|
||||
const bool_t defaultValue
|
||||
) {
|
||||
yyjson_val *val = yyjson_obj_get(obj, key);
|
||||
return val == NULL ? defaultValue : yyjson_get_bool(val);
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "dusk.h"
|
||||
#include "rpg/overworld/worldpos.h"
|
||||
#include "yyjson.h"
|
||||
|
||||
/**
|
||||
* Reads obj[key] as a string (falling back to defaultValue if the key is
|
||||
* absent and defaultValue is non-NULL) into dest, a fixed-capacity
|
||||
* char_t[destCapacity] item field. Fails rather than truncating/asserting
|
||||
* if the string doesn't fit - this is untrusted, authored file content,
|
||||
* not an in-memory invariant.
|
||||
*
|
||||
* @param obj The item's JSON object.
|
||||
* @param key Field name to read.
|
||||
* @param defaultValue Value to use if key is absent, or NULL to require it.
|
||||
* @param dest Destination buffer.
|
||||
* @param destCapacity Capacity of dest, including the null terminator.
|
||||
* @return true on success, false if the field is missing (with no
|
||||
* default) or exceeds destCapacity.
|
||||
*/
|
||||
bool_t cutsceneJsonCopyString(
|
||||
yyjson_val *obj,
|
||||
const char_t *key,
|
||||
const char_t *defaultValue,
|
||||
char_t *dest,
|
||||
const size_t destCapacity
|
||||
);
|
||||
|
||||
/**
|
||||
* Reads a 3-element JSON array of integers into a worldpos_t.
|
||||
*
|
||||
* @param arr JSON array value, expected to hold exactly 3 numbers.
|
||||
* @param out Set to the decoded position on success.
|
||||
* @return true if arr was a valid 3-element numeric array, false otherwise.
|
||||
*/
|
||||
bool_t cutsceneJsonReadWorldPos(yyjson_val *arr, worldpos_t *out);
|
||||
|
||||
/**
|
||||
* Reads obj[key] as an integer, falling back to defaultValue if the key
|
||||
* is absent.
|
||||
*
|
||||
* @param obj The item's JSON object.
|
||||
* @param key Field name to read.
|
||||
* @param defaultValue Value to use if key is absent.
|
||||
* @return The field's value, or defaultValue if absent.
|
||||
*/
|
||||
int32_t cutsceneJsonGetInt(
|
||||
yyjson_val *obj,
|
||||
const char_t *key,
|
||||
const int32_t defaultValue
|
||||
);
|
||||
|
||||
/**
|
||||
* Reads obj[key] as a float, falling back to defaultValue if the key is
|
||||
* absent.
|
||||
*
|
||||
* @param obj The item's JSON object.
|
||||
* @param key Field name to read.
|
||||
* @param defaultValue Value to use if key is absent.
|
||||
* @return The field's value, or defaultValue if absent.
|
||||
*/
|
||||
float_t cutsceneJsonGetFloat(
|
||||
yyjson_val *obj,
|
||||
const char_t *key,
|
||||
const float_t defaultValue
|
||||
);
|
||||
|
||||
/**
|
||||
* Reads obj[key] as a boolean, falling back to defaultValue if the key is
|
||||
* absent.
|
||||
*
|
||||
* @param obj The item's JSON object.
|
||||
* @param key Field name to read.
|
||||
* @param defaultValue Value to use if key is absent.
|
||||
* @return The field's value, or defaultValue if absent.
|
||||
*/
|
||||
bool_t cutsceneJsonGetBool(
|
||||
yyjson_val *obj,
|
||||
const char_t *key,
|
||||
const bool_t defaultValue
|
||||
);
|
||||
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "cutscenejsonpauseflags.h"
|
||||
#include "cutscenejsonenum.h"
|
||||
|
||||
static const cutscenejsonenumentry_t CUTSCENE_JSON_PAUSE_FLAG_TABLE[] = {
|
||||
{ "NPC", CUTSCENE_PAUSE_NPC },
|
||||
{ "PLAYER", CUTSCENE_PAUSE_PLAYER },
|
||||
{ "WORLD", CUTSCENE_PAUSE_WORLD },
|
||||
{ "BATTLE", CUTSCENE_PAUSE_BATTLE },
|
||||
};
|
||||
#define CUTSCENE_JSON_PAUSE_FLAG_TABLE_COUNT \
|
||||
(sizeof(CUTSCENE_JSON_PAUSE_FLAG_TABLE) / sizeof(cutscenejsonenumentry_t))
|
||||
|
||||
bool_t cutsceneJsonParsePauseFlags(yyjson_val *arr, cutscenepause_t *out) {
|
||||
if(!yyjson_is_arr(arr)) return false;
|
||||
|
||||
cutscenepause_t value = CUTSCENE_PAUSE_NONE;
|
||||
yyjson_arr_iter iter = yyjson_arr_iter_with(arr);
|
||||
yyjson_val *flagVal;
|
||||
while((flagVal = yyjson_arr_iter_next(&iter)) != NULL) {
|
||||
int32_t flagValue;
|
||||
if(!cutsceneJsonLookupEnumInsensitive(
|
||||
CUTSCENE_JSON_PAUSE_FLAG_TABLE, CUTSCENE_JSON_PAUSE_FLAG_TABLE_COUNT,
|
||||
yyjson_get_str(flagVal), &flagValue
|
||||
)) {
|
||||
return false;
|
||||
}
|
||||
value |= (cutscenepause_t)flagValue;
|
||||
}
|
||||
*out = value;
|
||||
return true;
|
||||
}
|
||||
@@ -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"
|
||||
#include "rpg/cutscene/cutscenepause.h"
|
||||
#include "yyjson.h"
|
||||
|
||||
/**
|
||||
* Parses a JSON array of pause flag name strings, OR-ing each into out.
|
||||
* Shared by the top-level "pause" field (assetCutsceneLoaderSync) and the
|
||||
* SET_PAUSE item's "flags" field - both authored as the same shape.
|
||||
*
|
||||
* @param arr JSON array of pause flag name strings.
|
||||
* @param out Set to the OR'd-together flags on success (CUTSCENE_PAUSE_NONE
|
||||
* if arr is empty).
|
||||
* @return true on success, false if arr is not an array or contains an
|
||||
* invalid flag name.
|
||||
*/
|
||||
bool_t cutsceneJsonParsePauseFlags(yyjson_val *arr, cutscenepause_t *out);
|
||||
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "cutscenejsonpool.h"
|
||||
|
||||
size_t cutsceneJsonPoolAlign(const size_t size) {
|
||||
return (size + 3) & ~((size_t)3);
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "dusk.h"
|
||||
|
||||
/**
|
||||
* Rounds size up to the next multiple of 4 - every pool entry starts
|
||||
* 4-byte aligned so worldpos_t/multi-byte reads out of it never trap on
|
||||
* alignment-sensitive hardware (e.g. PSP's MIPS core).
|
||||
*
|
||||
* @param size Size to round up.
|
||||
* @return size rounded up to the next multiple of 4.
|
||||
*/
|
||||
size_t cutsceneJsonPoolAlign(const size_t size);
|
||||
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "cutscenejsonscenetype.h"
|
||||
#include "cutscenejsonenum.h"
|
||||
|
||||
static const cutscenejsonenumentry_t CUTSCENE_JSON_SCENE_TYPE_TABLE[] = {
|
||||
{ "NULL", SCENE_TYPE_NULL },
|
||||
{ "INITIAL", SCENE_TYPE_INITIAL },
|
||||
{ "OVERWORLD", SCENE_TYPE_OVERWORLD },
|
||||
{ "BATTLE", SCENE_TYPE_BATTLE },
|
||||
};
|
||||
#define CUTSCENE_JSON_SCENE_TYPE_TABLE_COUNT \
|
||||
(sizeof(CUTSCENE_JSON_SCENE_TYPE_TABLE) / sizeof(cutscenejsonenumentry_t))
|
||||
|
||||
bool_t cutsceneJsonLookupSceneType(const char_t *name, scenetype_t *out) {
|
||||
int32_t value;
|
||||
if(!cutsceneJsonLookupEnumInsensitive(
|
||||
CUTSCENE_JSON_SCENE_TYPE_TABLE, CUTSCENE_JSON_SCENE_TYPE_TABLE_COUNT,
|
||||
name, &value
|
||||
)) {
|
||||
return false;
|
||||
}
|
||||
*out = (scenetype_t)value;
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "dusk.h"
|
||||
#include "scene/scenetype.h"
|
||||
|
||||
/**
|
||||
* Looks up name (case-insensitively) against the scene type table.
|
||||
*
|
||||
* @param name Name to search for.
|
||||
* @param out Set to the matching scene type on success.
|
||||
* @return true if a matching entry was found, false otherwise.
|
||||
*/
|
||||
bool_t cutsceneJsonLookupSceneType(const char_t *name, scenetype_t *out);
|
||||
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "cutscenejsonuiscreentype.h"
|
||||
#include "cutscenejsonenum.h"
|
||||
|
||||
static const cutscenejsonenumentry_t CUTSCENE_JSON_UI_SCREEN_TYPE_TABLE[] = {
|
||||
{ "MAIN_MENU", UI_SCREEN_TYPE_MAIN_MENU },
|
||||
};
|
||||
#define CUTSCENE_JSON_UI_SCREEN_TYPE_TABLE_COUNT \
|
||||
(sizeof(CUTSCENE_JSON_UI_SCREEN_TYPE_TABLE) / \
|
||||
sizeof(cutscenejsonenumentry_t))
|
||||
|
||||
bool_t cutsceneJsonLookupUiScreenType(
|
||||
const char_t *name,
|
||||
uiscreentype_t *out
|
||||
) {
|
||||
int32_t value;
|
||||
if(!cutsceneJsonLookupEnumInsensitive(
|
||||
CUTSCENE_JSON_UI_SCREEN_TYPE_TABLE,
|
||||
CUTSCENE_JSON_UI_SCREEN_TYPE_TABLE_COUNT, name, &value
|
||||
)) {
|
||||
return false;
|
||||
}
|
||||
*out = (uiscreentype_t)value;
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* Copyright (c) 2026 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "dusk.h"
|
||||
#include "rpg/cutscene/item/ui/cutsceneuishow.h"
|
||||
|
||||
/**
|
||||
* Looks up name (case-insensitively) against the UI screen type table.
|
||||
*
|
||||
* @param name Name to search for.
|
||||
* @param out Set to the matching screen type on success.
|
||||
* @return true if a matching entry was found, false otherwise.
|
||||
*/
|
||||
bool_t cutsceneJsonLookupUiScreenType(
|
||||
const char_t *name,
|
||||
uiscreentype_t *out
|
||||
);
|
||||
@@ -6,11 +6,9 @@
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "rpg/cutscene/item/cutsceneitembase.h"
|
||||
#include "rpg/overworld/maparea.h"
|
||||
|
||||
typedef struct cutsceneitem_s cutsceneitem_t;
|
||||
typedef union cutsceneitemdata_u cutsceneitemdata_t;
|
||||
|
||||
typedef struct {
|
||||
worldpos_t min;
|
||||
worldpos_t max;
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "rpg/cutscene/item/cutsceneitem.h"
|
||||
#include "rpg/cutscene/cutscenesystem.h"
|
||||
#include "rpg/overworld/maparea.h"
|
||||
#include "rpg/cutscene/item/json/cutscenejsonareaid.h"
|
||||
|
||||
void cutsceneMapAreaRemoveStart(
|
||||
const cutsceneitem_t *item,
|
||||
@@ -22,3 +23,18 @@ bool_t cutsceneMapAreaRemoveUpdate(
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
errorret_t cutsceneMapAreaRemoveLoad(
|
||||
yyjson_val *itemObj,
|
||||
cutsceneitem_t *item,
|
||||
uint8_t *pool,
|
||||
size_t *poolOffset
|
||||
) {
|
||||
if(!cutsceneJsonGetAreaId(
|
||||
yyjson_obj_get(itemObj, "areaId"), &item->mapAreaRemove.areaId
|
||||
)) {
|
||||
errorThrow("Cutscene item (MAP_AREA_REMOVE): invalid 'areaId'");
|
||||
}
|
||||
|
||||
errorOk();
|
||||
}
|
||||
|
||||
@@ -6,10 +6,7 @@
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "dusk.h"
|
||||
|
||||
typedef struct cutsceneitem_s cutsceneitem_t;
|
||||
typedef union cutsceneitemdata_u cutsceneitemdata_t;
|
||||
#include "rpg/cutscene/item/cutsceneitembase.h"
|
||||
|
||||
typedef struct {
|
||||
uint8_t areaId;
|
||||
@@ -38,3 +35,19 @@ bool_t cutsceneMapAreaRemoveUpdate(
|
||||
const cutsceneitem_t *item,
|
||||
cutsceneitemdata_t *data
|
||||
);
|
||||
|
||||
/**
|
||||
* Parses a MAP_AREA_REMOVE cutscene item's JSON fields into item.
|
||||
*
|
||||
* @param itemObj The item's JSON object.
|
||||
* @param item Destination item, already zeroed by the caller.
|
||||
* @param pool Unused (MAP_AREA_REMOVE needs no pool storage).
|
||||
* @param poolOffset Unused (MAP_AREA_REMOVE needs no pool storage).
|
||||
* @return Error code indicating success or failure of the parse.
|
||||
*/
|
||||
errorret_t cutsceneMapAreaRemoveLoad(
|
||||
yyjson_val *itemObj,
|
||||
cutsceneitem_t *item,
|
||||
uint8_t *pool,
|
||||
size_t *poolOffset
|
||||
);
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
#include "rpg/cutscene/cutscenesystem.h"
|
||||
#include "rpg/overworld/maparea.h"
|
||||
#include "assert/assert.h"
|
||||
#include "rpg/cutscene/item/json/cutscenejsonareaid.h"
|
||||
#include "rpg/cutscene/item/json/cutscenejsonpool.h"
|
||||
|
||||
void cutsceneMapAreaWaitStart(
|
||||
const cutsceneitem_t *item,
|
||||
@@ -38,3 +40,46 @@ bool_t cutsceneMapAreaWaitUpdate(
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
errorret_t cutsceneMapAreaWaitLoad(
|
||||
yyjson_val *itemObj,
|
||||
cutsceneitem_t *item,
|
||||
uint8_t *pool,
|
||||
size_t *poolOffset
|
||||
) {
|
||||
yyjson_val *areaIds = yyjson_obj_get(itemObj, "areaIds");
|
||||
size_t count = yyjson_arr_size(areaIds);
|
||||
if(
|
||||
!yyjson_is_arr(areaIds) || count == 0 ||
|
||||
count > CUTSCENE_MAP_AREA_WAIT_MAX
|
||||
) {
|
||||
errorThrow(
|
||||
"Cutscene item (MAP_AREA_WAIT): 'areaIds' must have 1-%u entries",
|
||||
(uint32_t)CUTSCENE_MAP_AREA_WAIT_MAX
|
||||
);
|
||||
}
|
||||
*poolOffset = cutsceneJsonPoolAlign(*poolOffset);
|
||||
uint8_t *dest = pool + *poolOffset;
|
||||
yyjson_arr_iter iter = yyjson_arr_iter_with(areaIds);
|
||||
yyjson_val *idVal;
|
||||
size_t i = 0;
|
||||
while((idVal = yyjson_arr_iter_next(&iter)) != NULL) {
|
||||
if(!cutsceneJsonGetAreaId(idVal, &dest[i])) {
|
||||
errorThrow(
|
||||
"Cutscene item (MAP_AREA_WAIT): areaIds[%u] is invalid", (uint32_t)i
|
||||
);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
item->mapAreaWait.areaIds = dest;
|
||||
item->mapAreaWait.count = (uint8_t)count;
|
||||
*poolOffset += count;
|
||||
|
||||
errorOk();
|
||||
}
|
||||
|
||||
size_t cutsceneMapAreaWaitPoolSize(yyjson_val *itemObj) {
|
||||
yyjson_val *areaIds = yyjson_obj_get(itemObj, "areaIds");
|
||||
if(!yyjson_is_arr(areaIds)) return 0;
|
||||
return yyjson_arr_size(areaIds);
|
||||
}
|
||||
|
||||
@@ -6,10 +6,7 @@
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "dusk.h"
|
||||
|
||||
typedef struct cutsceneitem_s cutsceneitem_t;
|
||||
typedef union cutsceneitemdata_u cutsceneitemdata_t;
|
||||
#include "rpg/cutscene/item/cutsceneitembase.h"
|
||||
|
||||
/** Maximum number of areas a single CUTSCENE_MAP_AREA_WAIT may watch. */
|
||||
#define CUTSCENE_MAP_AREA_WAIT_MAX 4
|
||||
@@ -47,3 +44,29 @@ bool_t cutsceneMapAreaWaitUpdate(
|
||||
const cutsceneitem_t *item,
|
||||
cutsceneitemdata_t *data
|
||||
);
|
||||
|
||||
/**
|
||||
* Parses a MAP_AREA_WAIT cutscene item's JSON fields into item, writing its
|
||||
* "areaIds" array into pool at *poolOffset and advancing it.
|
||||
*
|
||||
* @param itemObj The item's JSON object.
|
||||
* @param item Destination item, already zeroed by the caller.
|
||||
* @param pool Base pointer of the entry's pool allocation.
|
||||
* @param poolOffset In/out cursor into pool.
|
||||
* @return Error code indicating success or failure of the parse.
|
||||
*/
|
||||
errorret_t cutsceneMapAreaWaitLoad(
|
||||
yyjson_val *itemObj,
|
||||
cutsceneitem_t *item,
|
||||
uint8_t *pool,
|
||||
size_t *poolOffset
|
||||
);
|
||||
|
||||
/**
|
||||
* Computes how many pool bytes this MAP_AREA_WAIT item's "areaIds" array
|
||||
* will need.
|
||||
*
|
||||
* @param itemObj The item's JSON object.
|
||||
* @return Pool bytes required (0 if "areaIds" is missing/not an array).
|
||||
*/
|
||||
size_t cutsceneMapAreaWaitPoolSize(yyjson_val *itemObj);
|
||||
|
||||
@@ -31,3 +31,25 @@ bool_t cutsceneSaveDeviceCheckUpdate(
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
errorret_t cutsceneSaveDeviceCheckLoad(
|
||||
yyjson_val *itemObj,
|
||||
cutsceneitem_t *item,
|
||||
uint8_t *pool,
|
||||
size_t *poolOffset
|
||||
) {
|
||||
const char_t *successMarker =
|
||||
yyjson_get_str(yyjson_obj_get(itemObj, "successMarker"));
|
||||
const char_t *failureMarker =
|
||||
yyjson_get_str(yyjson_obj_get(itemObj, "failureMarker"));
|
||||
if(successMarker == NULL || failureMarker == NULL) {
|
||||
errorThrow(
|
||||
"Cutscene item (SAVE_DEVICE_CHECK): needs 'successMarker'/"
|
||||
"'failureMarker'"
|
||||
);
|
||||
}
|
||||
item->saveDeviceCheck.successMarker = successMarker;
|
||||
item->saveDeviceCheck.failureMarker = failureMarker;
|
||||
|
||||
errorOk();
|
||||
}
|
||||
|
||||
@@ -6,10 +6,7 @@
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "dusk.h"
|
||||
|
||||
typedef struct cutsceneitem_s cutsceneitem_t;
|
||||
typedef union cutsceneitemdata_u cutsceneitemdata_t;
|
||||
#include "rpg/cutscene/item/cutsceneitembase.h"
|
||||
|
||||
typedef struct {
|
||||
const char_t *successMarker;
|
||||
@@ -43,3 +40,19 @@ bool_t cutsceneSaveDeviceCheckUpdate(
|
||||
const cutsceneitem_t *item,
|
||||
cutsceneitemdata_t *data
|
||||
);
|
||||
|
||||
/**
|
||||
* Parses a SAVE_DEVICE_CHECK cutscene item's JSON fields into item.
|
||||
*
|
||||
* @param itemObj The item's JSON object.
|
||||
* @param item Destination item, already zeroed by the caller.
|
||||
* @param pool Unused (SAVE_DEVICE_CHECK needs no pool storage).
|
||||
* @param poolOffset Unused (SAVE_DEVICE_CHECK needs no pool storage).
|
||||
* @return Error code indicating success or failure of the parse.
|
||||
*/
|
||||
errorret_t cutsceneSaveDeviceCheckLoad(
|
||||
yyjson_val *itemObj,
|
||||
cutsceneitem_t *item,
|
||||
uint8_t *pool,
|
||||
size_t *poolOffset
|
||||
);
|
||||
|
||||
@@ -29,3 +29,25 @@ bool_t cutsceneSaveLoadAllSlotsUpdate(
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
errorret_t cutsceneSaveLoadAllSlotsLoad(
|
||||
yyjson_val *itemObj,
|
||||
cutsceneitem_t *item,
|
||||
uint8_t *pool,
|
||||
size_t *poolOffset
|
||||
) {
|
||||
const char_t *successMarker =
|
||||
yyjson_get_str(yyjson_obj_get(itemObj, "successMarker"));
|
||||
const char_t *failureMarker =
|
||||
yyjson_get_str(yyjson_obj_get(itemObj, "failureMarker"));
|
||||
if(successMarker == NULL || failureMarker == NULL) {
|
||||
errorThrow(
|
||||
"Cutscene item (SAVE_LOAD_ALL_SLOTS): needs 'successMarker'/"
|
||||
"'failureMarker'"
|
||||
);
|
||||
}
|
||||
item->saveLoadAllSlots.successMarker = successMarker;
|
||||
item->saveLoadAllSlots.failureMarker = failureMarker;
|
||||
|
||||
errorOk();
|
||||
}
|
||||
|
||||
@@ -6,10 +6,7 @@
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "dusk.h"
|
||||
|
||||
typedef struct cutsceneitem_s cutsceneitem_t;
|
||||
typedef union cutsceneitemdata_u cutsceneitemdata_t;
|
||||
#include "rpg/cutscene/item/cutsceneitembase.h"
|
||||
|
||||
typedef struct {
|
||||
const char_t *successMarker;
|
||||
@@ -42,3 +39,19 @@ bool_t cutsceneSaveLoadAllSlotsUpdate(
|
||||
const cutsceneitem_t *item,
|
||||
cutsceneitemdata_t *data
|
||||
);
|
||||
|
||||
/**
|
||||
* Parses a SAVE_LOAD_ALL_SLOTS cutscene item's JSON fields into item.
|
||||
*
|
||||
* @param itemObj The item's JSON object.
|
||||
* @param item Destination item, already zeroed by the caller.
|
||||
* @param pool Unused (SAVE_LOAD_ALL_SLOTS needs no pool storage).
|
||||
* @param poolOffset Unused (SAVE_LOAD_ALL_SLOTS needs no pool storage).
|
||||
* @return Error code indicating success or failure of the parse.
|
||||
*/
|
||||
errorret_t cutsceneSaveLoadAllSlotsLoad(
|
||||
yyjson_val *itemObj,
|
||||
cutsceneitem_t *item,
|
||||
uint8_t *pool,
|
||||
size_t *poolOffset
|
||||
);
|
||||
|
||||
@@ -8,6 +8,9 @@
|
||||
#include "rpg/cutscene/item/cutsceneitem.h"
|
||||
#include "rpg/cutscene/cutscenesystem.h"
|
||||
#include "rpg/entity/entity.h"
|
||||
#include "rpg/cutscene/item/json/cutscenejsonentityindex.h"
|
||||
#include "rpg/cutscene/item/json/cutscenejsonemoji.h"
|
||||
#include "rpg/cutscene/item/json/cutscenejsonfield.h"
|
||||
|
||||
void cutsceneEmojiStart(
|
||||
const cutsceneitem_t *item,
|
||||
@@ -23,3 +26,26 @@ bool_t cutsceneEmojiUpdate(
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
errorret_t cutsceneEmojiLoad(
|
||||
yyjson_val *itemObj,
|
||||
cutsceneitem_t *item,
|
||||
uint8_t *pool,
|
||||
size_t *poolOffset
|
||||
) {
|
||||
if(!cutsceneJsonGetEntityIndex(
|
||||
yyjson_obj_get(itemObj, "entityIndex"), &item->emoji.entityIndex
|
||||
)) {
|
||||
errorThrow("Cutscene item (EMOJI): invalid 'entityIndex'");
|
||||
}
|
||||
item->emoji.duration = cutsceneJsonGetFloat(itemObj, "duration", 0.0f);
|
||||
uiemojitype_t emojiValue;
|
||||
if(!cutsceneJsonLookupEmoji(
|
||||
yyjson_get_str(yyjson_obj_get(itemObj, "emojiType")), &emojiValue
|
||||
)) {
|
||||
errorThrow("Cutscene item (EMOJI): invalid 'emojiType'");
|
||||
}
|
||||
item->emoji.emojiType = emojiValue;
|
||||
|
||||
errorOk();
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user