Add battle abilities and wire them into START_BATTLE cutscene parsing

Adds a battleability_t enum (starting with FIRE) and a fixed
abilities[8] array on battlefighter_t. Extends the START_BATTLE
cutscene item to parse an optional per-enemy "abilities" JSON array
(via a new cutsceneJsonLookupBattleAbility name lookup) and copies
abilities onto every spawned fighter, from the party roster for
allies and from the parsed config for enemies.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
This commit is contained in:
2026-09-12 22:30:12 -05:00
co-authored by Claude Sonnet 5
parent b8cbd8ff6a
commit ffb375faeb
7 changed files with 114 additions and 1 deletions
+17
View File
@@ -0,0 +1,17 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "error/error.h"
typedef enum {
BATTLE_ABILITY_NULL,
BATTLE_ABILITY_FIRE,
BATTLE_ABILITY_COUNT
} battleability_t;
+4
View File
@@ -7,6 +7,9 @@
#pragma once
#include "error/error.h"
#include "battleability.h"
#define BATTLE_FIGHTER_ABILITY_COUNT_MAX 8
// An empty status means the slot in BATTLE.fighters is unused.
typedef enum {
@@ -55,6 +58,7 @@ typedef struct {
uint16_t mpMax;
battlefighterstats_t stats;
battleability_t abilities[BATTLE_FIGHTER_ABILITY_COUNT_MAX];
} battlefighter_t;
/**
@@ -10,7 +10,9 @@
#include "scene/scene.h"
#include "save/save.h"
#include "rpg/cutscene/item/json/cutscenejsonbattleencounter.h"
#include "rpg/cutscene/item/json/cutscenejsonbattleability.h"
#include "rpg/cutscene/item/json/cutscenejsonfield.h"
#include "util/memory.h"
void cutsceneStartBattleStart(
const cutsceneitem_t *item,
@@ -34,14 +36,18 @@ void cutsceneStartBattleStart(
fighter->health = member->health;
fighter->mp = member->mp;
fighter->status = member->status;
memoryCopy(fighter->abilities, member->abilities, sizeof(fighter->abilities));
}
for(uint8_t i = 0; i < config->enemyCount; i++) {
const cutscenestartbattleenemy_t *enemy = &config->enemies[i];
battleAddFighter(
battlefighter_t *fighter = battleAddFighter(
BATTLE_FIGHTER_TEAM_ENEMY, BATTLE_FIGHTER_CONTROLLER_AI,
enemy->stats, enemy->healthMax, enemy->mpMax
);
if(fighter == NULL) continue;
memoryCopy(fighter->abilities, enemy->abilities, sizeof(fighter->abilities));
}
battleStart(config->encounterType, config->fleeAvailable);
@@ -162,6 +168,37 @@ errorret_t cutsceneStartBattleLoad(
(uint16_t)yyjson_get_int(yyjson_obj_get(enemyVal, "healthMax"));
enemy->mpMax =
(uint16_t)yyjson_get_int(yyjson_obj_get(enemyVal, "mpMax"));
yyjson_val *abilities = yyjson_obj_get(enemyVal, "abilities");
if(abilities != NULL) {
size_t abilityCount = yyjson_arr_size(abilities);
if(!yyjson_is_arr(abilities) ||
abilityCount > BATTLE_FIGHTER_ABILITY_COUNT_MAX) {
errorThrow(
"Cutscene item (START_BATTLE): enemies[%u].abilities must have "
"0-%u entries",
(uint32_t)e, (uint32_t)BATTLE_FIGHTER_ABILITY_COUNT_MAX
);
}
yyjson_arr_iter abilityIter = yyjson_arr_iter_with(abilities);
yyjson_val *abilityVal;
size_t a = 0;
while((abilityVal = yyjson_arr_iter_next(&abilityIter)) != NULL) {
battleability_t ability;
if(!cutsceneJsonLookupBattleAbility(
yyjson_get_str(abilityVal), &ability
)) {
errorThrow(
"Cutscene item (START_BATTLE): enemies[%u].abilities[%u] is "
"invalid",
(uint32_t)e, (uint32_t)a
);
}
enemy->abilities[a] = ability;
a++;
}
}
e++;
}
@@ -16,6 +16,7 @@ typedef struct {
battlefighterstats_t stats;
uint16_t healthMax;
uint16_t mpMax;
battleability_t abilities[BATTLE_FIGHTER_ABILITY_COUNT_MAX];
} cutscenestartbattleenemy_t;
typedef struct {
@@ -16,6 +16,7 @@ target_sources(${DUSK_LIBRARY_TARGET_NAME}
cutscenejsonentitytype.c
cutscenejsonentitydir.c
cutscenejsonbattleencounter.c
cutscenejsonbattleability.c
cutscenejsonbattlestate.c
cutscenejsonscenetype.c
cutscenejsonuiscreentype.c
@@ -0,0 +1,31 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "cutscenejsonbattleability.h"
#include "cutscenejsonenum.h"
static const cutscenejsonenumentry_t CUTSCENE_JSON_BATTLE_ABILITY_TABLE[] = {
{ "FIRE", BATTLE_ABILITY_FIRE },
};
#define CUTSCENE_JSON_BATTLE_ABILITY_TABLE_COUNT \
(sizeof(CUTSCENE_JSON_BATTLE_ABILITY_TABLE) / \
sizeof(cutscenejsonenumentry_t))
bool_t cutsceneJsonLookupBattleAbility(
const char_t *name,
battleability_t *out
) {
int32_t value;
if(!cutsceneJsonLookupEnumInsensitive(
CUTSCENE_JSON_BATTLE_ABILITY_TABLE,
CUTSCENE_JSON_BATTLE_ABILITY_TABLE_COUNT, name, &value
)) {
return false;
}
*out = (battleability_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/battle/battleability.h"
/**
* Looks up name (case-insensitively) against the battle ability table.
*
* @param name Name to search for.
* @param out Set to the matching ability on success.
* @return true if a matching entry was found, false otherwise.
*/
bool_t cutsceneJsonLookupBattleAbility(
const char_t *name,
battleability_t *out
);