Battle changes, first pass.
This commit is contained in:
@@ -1,11 +1,21 @@
|
|||||||
{
|
{
|
||||||
"moves": {
|
"moves": {
|
||||||
"fire": {
|
"fire": {
|
||||||
"ability": "FIRE",
|
// Target flags
|
||||||
"power": 12,
|
"enemies": true,
|
||||||
"mpCost": 4,
|
"allies": true,
|
||||||
"target": "SINGLE_ENEMY",
|
"multiple": false,
|
||||||
"cutscene": "cutscenes/battle/fire.jsonc"
|
"self": true,
|
||||||
|
"default": "enemy",
|
||||||
|
"target": "SINGLE_ENEMY"
|
||||||
|
},
|
||||||
|
|
||||||
|
"slash": {
|
||||||
|
"enemies": true,
|
||||||
|
"allies": true,
|
||||||
|
"self": false,
|
||||||
|
"default": "enemy",
|
||||||
|
"target": "SINGLE_ENEMY"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"type": "MODAL",
|
||||||
|
"title": "BATTLE TEST",
|
||||||
|
"message": "BATTLE TEST"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"type": "MODAL",
|
||||||
|
"title": "BATTLE TEST",
|
||||||
|
"message": "BATTLE TEST"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -266,6 +266,10 @@ msgstr "loading"
|
|||||||
msgid "ui.autosave.saving"
|
msgid "ui.autosave.saving"
|
||||||
msgstr "SAVING"
|
msgstr "SAVING"
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Items
|
||||||
|
#
|
||||||
msgid "item.potion.name"
|
msgid "item.potion.name"
|
||||||
msgstr "Potion"
|
msgstr "Potion"
|
||||||
|
|
||||||
@@ -274,3 +278,12 @@ msgstr "Potato"
|
|||||||
|
|
||||||
msgid "item.apple.name"
|
msgid "item.apple.name"
|
||||||
msgstr "Apple"
|
msgstr "Apple"
|
||||||
|
|
||||||
|
#
|
||||||
|
# Moves
|
||||||
|
#
|
||||||
|
msgid "move.fire.name"
|
||||||
|
msgstr "Fire"
|
||||||
|
|
||||||
|
msgid "move.slash.name"
|
||||||
|
msgstr "Slash"
|
||||||
@@ -12,13 +12,16 @@
|
|||||||
// "DSK2" - distinct from a plain zip's "PK\x03\x04" so a stray plain zip
|
// "DSK2" - distinct from a plain zip's "PK\x03\x04" so a stray plain zip
|
||||||
// never gets misread as a valid dusk.dsk.
|
// never gets misread as a valid dusk.dsk.
|
||||||
#define ASSET_DSK_MAGIC_SIZE 4
|
#define ASSET_DSK_MAGIC_SIZE 4
|
||||||
#define ASSET_DSK_MAGIC "DSK2"
|
#define ASSET_DSK_MAGIC "DSK"
|
||||||
#define ASSET_DSK_VERSION 2
|
#define ASSET_DSK_VERSION 2
|
||||||
|
|
||||||
// magic(4) + version(4) + size(4) + checksum(4), all little-endian
|
// Magic + version + size + checksum
|
||||||
// regardless of host - see assetDskParseHeader. The zip archive itself
|
#define ASSET_DSK_HEADER_SIZE ( \
|
||||||
// starts immediately after, at ASSET_DSK_HEADER_SIZE.
|
ASSET_DSK_MAGIC_SIZE + \
|
||||||
#define ASSET_DSK_HEADER_SIZE 16
|
sizeof(uint32_t) + \
|
||||||
|
sizeof(uint32_t) + \
|
||||||
|
sizeof(uint32_t) \
|
||||||
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parsed dusk.dsk (DSK2 format) header. dusk.dsk is a single uncompressed
|
* Parsed dusk.dsk (DSK2 format) header. dusk.dsk is a single uncompressed
|
||||||
|
|||||||
@@ -7,6 +7,8 @@
|
|||||||
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
||||||
PUBLIC
|
PUBLIC
|
||||||
battle.c
|
battle.c
|
||||||
battlefighter.c
|
|
||||||
party.c
|
party.c
|
||||||
)
|
)
|
||||||
|
|
||||||
|
add_subdirectory(fighter)
|
||||||
|
add_subdirectory(move)
|
||||||
|
|||||||
@@ -10,10 +10,14 @@
|
|||||||
#include "util/memory.h"
|
#include "util/memory.h"
|
||||||
#include "rpg/cutscene/cutscenesystem.h"
|
#include "rpg/cutscene/cutscenesystem.h"
|
||||||
|
|
||||||
|
// TEMPORARY: hardcoded pending a real moves.jsonc-backed registry lookup.
|
||||||
|
#define BATTLE_MOVE_ID_ATTACK ((battlemoveid_t)1)
|
||||||
|
|
||||||
battle_t BATTLE;
|
battle_t BATTLE;
|
||||||
|
|
||||||
void battleInit(void) {
|
void battleInit(void) {
|
||||||
memoryZero(&BATTLE, sizeof(battle_t));
|
memoryZero(&BATTLE, sizeof(battle_t));
|
||||||
|
|
||||||
for(uint8_t i = 0; i < BATTLE_FIGHTER_COUNT_MAX; i++) {
|
for(uint8_t i = 0; i < BATTLE_FIGHTER_COUNT_MAX; i++) {
|
||||||
BATTLE.fighters[i].id = i;
|
BATTLE.fighters[i].id = i;
|
||||||
}
|
}
|
||||||
@@ -103,18 +107,14 @@ battleresult_t battleCheckResult(void) {
|
|||||||
return BATTLE.result;
|
return BATTLE.result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void battleQueueAction(
|
void battleQueueMove(
|
||||||
const uint8_t fighterIndex,
|
const uint8_t fighterIndex,
|
||||||
const battleactiontype_t type,
|
const battlemoveid_t move,
|
||||||
const uint8_t targetIndex
|
const uint8_t targetIndex
|
||||||
) {
|
) {
|
||||||
battleaction_t *action = &BATTLE.actions[fighterIndex];
|
battlemoveaction_t *action = &BATTLE.moves[fighterIndex];
|
||||||
action->type = type;
|
action->move = move;
|
||||||
action->targetIndex = targetIndex;
|
action->targetIndex = targetIndex;
|
||||||
|
|
||||||
if(BATTLE.onActionDecided != NULL) {
|
|
||||||
BATTLE.onActionDecided(&BATTLE.fighters[fighterIndex], action);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void battlePlayerAttack(const uint8_t targetIndex) {
|
void battlePlayerAttack(const uint8_t targetIndex) {
|
||||||
@@ -123,7 +123,7 @@ void battlePlayerAttack(const uint8_t targetIndex) {
|
|||||||
if(targetIndex >= BATTLE_FIGHTER_COUNT_MAX) return;
|
if(targetIndex >= BATTLE_FIGHTER_COUNT_MAX) return;
|
||||||
if(!battleFighterIsAlive(&BATTLE.fighters[targetIndex])) return;
|
if(!battleFighterIsAlive(&BATTLE.fighters[targetIndex])) return;
|
||||||
|
|
||||||
battleQueueAction(fighter->id, BATTLE_ACTION_ATTACK, targetIndex);
|
battleQueueMove(fighter->id, BATTLE_MOVE_ID_ATTACK, targetIndex);
|
||||||
BATTLE.selectionIndex++;
|
BATTLE.selectionIndex++;
|
||||||
battleAdvanceSelection();
|
battleAdvanceSelection();
|
||||||
}
|
}
|
||||||
@@ -220,9 +220,11 @@ void battleMoveTeamFirst(const battlefighterteam_t team) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
battlefighter_t *battleAIChooseTarget(const battlefighter_t *fighter) {
|
battlefighter_t *battleAIChooseTarget(const battlefighter_t *fighter) {
|
||||||
const battlefighterteam_t enemyTeam =
|
const battlefighterteam_t enemyTeam = (
|
||||||
fighter->team == BATTLE_FIGHTER_TEAM_ALLY ?
|
fighter->team == BATTLE_FIGHTER_TEAM_ALLY ?
|
||||||
BATTLE_FIGHTER_TEAM_ENEMY : BATTLE_FIGHTER_TEAM_ALLY;
|
BATTLE_FIGHTER_TEAM_ENEMY :
|
||||||
|
BATTLE_FIGHTER_TEAM_ALLY
|
||||||
|
);
|
||||||
|
|
||||||
battlefighter_t *weakest = NULL;
|
battlefighter_t *weakest = NULL;
|
||||||
for(uint8_t i = 0; i < BATTLE_FIGHTER_COUNT_MAX; i++) {
|
for(uint8_t i = 0; i < BATTLE_FIGHTER_COUNT_MAX; i++) {
|
||||||
@@ -238,9 +240,7 @@ battlefighter_t *battleAIChooseTarget(const battlefighter_t *fighter) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void battleSetState(const battlestate_t next) {
|
void battleSetState(const battlestate_t next) {
|
||||||
const battlestate_t previous = BATTLE.state;
|
|
||||||
BATTLE.state = next;
|
BATTLE.state = next;
|
||||||
if(BATTLE.onStateChanged != NULL) BATTLE.onStateChanged(previous, next);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void battleSetResult(const battleresult_t result) {
|
void battleSetResult(const battleresult_t result) {
|
||||||
@@ -254,7 +254,7 @@ bool_t battleFighterNeedsDecision(
|
|||||||
) {
|
) {
|
||||||
return battleFighterIsAlive(&BATTLE.fighters[fighterIndex])
|
return battleFighterIsAlive(&BATTLE.fighters[fighterIndex])
|
||||||
&& BATTLE.fighters[fighterIndex].controller == controller
|
&& BATTLE.fighters[fighterIndex].controller == controller
|
||||||
&& BATTLE.actions[fighterIndex].type == BATTLE_ACTION_NONE;
|
&& BATTLE.moves[fighterIndex].move == BATTLE_MOVE_ID_NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void battleAdvanceSelection(void) {
|
void battleAdvanceSelection(void) {
|
||||||
@@ -272,10 +272,10 @@ void battleAdvanceSelection(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void battleUpdatePreRound(void) {
|
void battleUpdatePreRound(void) {
|
||||||
// No need to clear BATTLE.actions here: every living fighter's action is
|
// No need to clear BATTLE.moves here: every living fighter's move is
|
||||||
// unconditionally reset to BATTLE_ACTION_NONE as it's processed in
|
// unconditionally reset to BATTLE_MOVE_ID_NULL as it's processed in
|
||||||
// battleUpdateMovesExecuting, and round 1 starts pre-zeroed by
|
// battleUpdateMovesExecuting, and round 1 starts pre-zeroed by
|
||||||
// battleInit(). Clearing it here would also wipe out any action a
|
// battleInit(). Clearing it here would also wipe out any move a
|
||||||
// cutscene force-queued while parked at BATTLE_STATE_PRE_ROUND.
|
// cutscene force-queued while parked at BATTLE_STATE_PRE_ROUND.
|
||||||
battleBuildExecutionOrder(BATTLE.round == 1);
|
battleBuildExecutionOrder(BATTLE.round == 1);
|
||||||
|
|
||||||
@@ -295,7 +295,7 @@ void battleUpdateAiSelection(void) {
|
|||||||
battleAIChooseTarget(&BATTLE.fighters[fighterIndex]);
|
battleAIChooseTarget(&BATTLE.fighters[fighterIndex]);
|
||||||
if(target == NULL) continue;
|
if(target == NULL) continue;
|
||||||
|
|
||||||
battleQueueAction(fighterIndex, BATTLE_ACTION_ATTACK, target->id);
|
battleQueueMove(fighterIndex, BATTLE_MOVE_ID_ATTACK, target->id);
|
||||||
}
|
}
|
||||||
|
|
||||||
BATTLE.executionIndex = 0;
|
BATTLE.executionIndex = 0;
|
||||||
@@ -312,12 +312,12 @@ void battleUpdateMovesExecuting(void) {
|
|||||||
battlefighter_t *fighter = &BATTLE.fighters[fighterIndex];
|
battlefighter_t *fighter = &BATTLE.fighters[fighterIndex];
|
||||||
if(!battleFighterIsAlive(fighter)) return;
|
if(!battleFighterIsAlive(fighter)) return;
|
||||||
|
|
||||||
battleaction_t *action = &BATTLE.actions[fighterIndex];
|
battlemoveaction_t *action = &BATTLE.moves[fighterIndex];
|
||||||
if(action->type == BATTLE_ACTION_ATTACK) {
|
if(action->move == BATTLE_MOVE_ID_ATTACK) {
|
||||||
battlefighter_t *target = &BATTLE.fighters[action->targetIndex];
|
battlefighter_t *target = &BATTLE.fighters[action->targetIndex];
|
||||||
if(battleFighterIsAlive(target)) battleResolveAttack(fighter, target);
|
if(battleFighterIsAlive(target)) battleResolveAttack(fighter, target);
|
||||||
}
|
}
|
||||||
action->type = BATTLE_ACTION_NONE;
|
action->move = BATTLE_MOVE_ID_NULL;
|
||||||
|
|
||||||
battleCheckResult();
|
battleCheckResult();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,8 +6,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "battlefighter.h"
|
#include "rpg/battle/fighter/battlefighter.h"
|
||||||
#include "battleaction.h"
|
#include "rpg/battle/move/battlemove.h"
|
||||||
|
|
||||||
#define BATTLE_FIGHTER_COUNT_MAX 8
|
#define BATTLE_FIGHTER_COUNT_MAX 8
|
||||||
|
|
||||||
@@ -43,15 +43,10 @@ typedef enum {
|
|||||||
BATTLE_STATE_COUNT
|
BATTLE_STATE_COUNT
|
||||||
} battlestate_t;
|
} battlestate_t;
|
||||||
|
|
||||||
typedef void (*battlestatechangedcallback_t)(
|
|
||||||
const battlestate_t previous,
|
|
||||||
const battlestate_t next
|
|
||||||
);
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
battlestate_t state;
|
battlestate_t state;
|
||||||
battlefighter_t fighters[BATTLE_FIGHTER_COUNT_MAX];
|
battlefighter_t fighters[BATTLE_FIGHTER_COUNT_MAX];
|
||||||
battleaction_t actions[BATTLE_FIGHTER_COUNT_MAX];
|
battlemoveaction_t moves[BATTLE_FIGHTER_COUNT_MAX];
|
||||||
|
|
||||||
battleencountertype_t encounterType;
|
battleencountertype_t encounterType;
|
||||||
bool_t fleeAvailable;
|
bool_t fleeAvailable;
|
||||||
@@ -66,9 +61,6 @@ typedef struct {
|
|||||||
// Cursor into executionOrder used by BATTLE_STATE_PLAYER_SELECTION to find
|
// Cursor into executionOrder used by BATTLE_STATE_PLAYER_SELECTION to find
|
||||||
// the next player-controlled fighter that still needs a decision.
|
// the next player-controlled fighter that still needs a decision.
|
||||||
uint8_t selectionIndex;
|
uint8_t selectionIndex;
|
||||||
|
|
||||||
battlestatechangedcallback_t onStateChanged;
|
|
||||||
battleactiondecidedcallback_t onActionDecided;
|
|
||||||
} battle_t;
|
} battle_t;
|
||||||
|
|
||||||
extern battle_t BATTLE;
|
extern battle_t BATTLE;
|
||||||
@@ -163,25 +155,24 @@ void battleResolveAttack(
|
|||||||
battleresult_t battleCheckResult(void);
|
battleresult_t battleCheckResult(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Queues an action for a fighter to perform once BATTLE_STATE_MOVES_EXECUTING
|
* Queues a move for a fighter to perform once BATTLE_STATE_MOVES_EXECUTING
|
||||||
* reaches them this round, overwriting any action already queued for that
|
* reaches them this round, overwriting any move already queued for that
|
||||||
* fighter. Fires BATTLE.onActionDecided.
|
* fighter.
|
||||||
*
|
*
|
||||||
* @param fighterIndex Index into BATTLE.fighters of the deciding fighter.
|
* @param fighterIndex Index into BATTLE.fighters of the deciding fighter.
|
||||||
* @param type The type of action to perform.
|
* @param move The move to perform.
|
||||||
* @param targetIndex Index into BATTLE.fighters of the target, meaningful
|
* @param targetIndex Index into BATTLE.fighters of the target.
|
||||||
* for BATTLE_ACTION_ATTACK.
|
|
||||||
*/
|
*/
|
||||||
void battleQueueAction(
|
void battleQueueMove(
|
||||||
const uint8_t fighterIndex,
|
const uint8_t fighterIndex,
|
||||||
const battleactiontype_t type,
|
const battlemoveid_t move,
|
||||||
const uint8_t targetIndex
|
const uint8_t targetIndex
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Submits the currently-selecting fighter's attack against a target, if the
|
* Submits the currently-selecting fighter's attack against a target, if the
|
||||||
* battle is in BATTLE_STATE_PLAYER_SELECTION and awaiting a decision.
|
* battle is in BATTLE_STATE_PLAYER_SELECTION and awaiting a decision.
|
||||||
* Queues the action and advances the selection cursor.
|
* Queues the move and advances the selection cursor.
|
||||||
*
|
*
|
||||||
* @param targetIndex Index into BATTLE.fighters of the target.
|
* @param targetIndex Index into BATTLE.fighters of the target.
|
||||||
*/
|
*/
|
||||||
@@ -230,8 +221,7 @@ void battleMoveTeamFirst(const battlefighterteam_t team);
|
|||||||
battlefighter_t *battleAIChooseTarget(const battlefighter_t *fighter);
|
battlefighter_t *battleAIChooseTarget(const battlefighter_t *fighter);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets BATTLE.state and fires BATTLE.onStateChanged with the previous and
|
* Sets BATTLE.state.
|
||||||
* new state.
|
|
||||||
*
|
*
|
||||||
* @param next The state to transition to.
|
* @param next The state to transition to.
|
||||||
*/
|
*/
|
||||||
@@ -247,13 +237,13 @@ void battleSetResult(const battleresult_t result);
|
|||||||
/**
|
/**
|
||||||
* Checks whether a fighter is a live, undecided candidate for the given
|
* Checks whether a fighter is a live, undecided candidate for the given
|
||||||
* controller -- i.e. whether PLAYER_SELECTION or AI_SELECTION should still
|
* controller -- i.e. whether PLAYER_SELECTION or AI_SELECTION should still
|
||||||
* be deciding an action for it this round.
|
* be deciding a move for it this round.
|
||||||
*
|
*
|
||||||
* @param fighterIndex Index into BATTLE.fighters to check.
|
* @param fighterIndex Index into BATTLE.fighters to check.
|
||||||
* @param controller The controller PLAYER_SELECTION/AI_SELECTION is
|
* @param controller The controller PLAYER_SELECTION/AI_SELECTION is
|
||||||
* currently deciding for.
|
* currently deciding for.
|
||||||
* @return True if the fighter is alive, matches controller, and has no
|
* @return True if the fighter is alive, matches controller, and has no
|
||||||
* action queued yet.
|
* move queued yet.
|
||||||
*/
|
*/
|
||||||
bool_t battleFighterNeedsDecision(
|
bool_t battleFighterNeedsDecision(
|
||||||
const uint8_t fighterIndex,
|
const uint8_t fighterIndex,
|
||||||
@@ -280,7 +270,7 @@ void battleUpdatePreRound(void);
|
|||||||
void battleUpdateAiSelection(void);
|
void battleUpdateAiSelection(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles BATTLE_STATE_MOVES_EXECUTING: resolves one queued action from
|
* Handles BATTLE_STATE_MOVES_EXECUTING: resolves one queued move from
|
||||||
* BATTLE.executionOrder per call, or transitions to BATTLE_STATE_POST_ROUND
|
* BATTLE.executionOrder per call, or transitions to BATTLE_STATE_POST_ROUND
|
||||||
* once every fighter this round has been processed.
|
* once every fighter this round has been processed.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -1,27 +0,0 @@
|
|||||||
/**
|
|
||||||
* Copyright (c) 2026 Dominic Masters
|
|
||||||
*
|
|
||||||
* This software is released under the MIT License.
|
|
||||||
* https://opensource.org/licenses/MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
#include "error/error.h"
|
|
||||||
#include "battlefighter.h"
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
BATTLE_ACTION_NONE, // No action decided yet for this fighter this round.
|
|
||||||
BATTLE_ACTION_ATTACK,
|
|
||||||
|
|
||||||
BATTLE_ACTION_COUNT
|
|
||||||
} battleactiontype_t;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
battleactiontype_t type;
|
|
||||||
uint8_t targetIndex; // Meaningful for BATTLE_ACTION_ATTACK.
|
|
||||||
} battleaction_t;
|
|
||||||
|
|
||||||
typedef void (*battleactiondecidedcallback_t)(
|
|
||||||
const battlefighter_t *fighter,
|
|
||||||
const battleaction_t *action
|
|
||||||
);
|
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
# Copyright (c) 2026 Dominic Masters
|
||||||
|
#
|
||||||
|
# This software is released under the MIT License.
|
||||||
|
# https://opensource.org/licenses/MIT
|
||||||
|
|
||||||
|
# Sources
|
||||||
|
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
||||||
|
PUBLIC
|
||||||
|
battlefighter.c
|
||||||
|
)
|
||||||
@@ -7,46 +7,15 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "error/error.h"
|
#include "error/error.h"
|
||||||
#include "battleability.h"
|
#include "rpg/battle/move/battlemove.h"
|
||||||
|
#include "rpg/battle/fighter/battlefighterstatus.h"
|
||||||
|
#include "rpg/battle/fighter/battlefighterteam.h"
|
||||||
|
#include "rpg/battle/fighter/battlefightercontroller.h"
|
||||||
|
#include "rpg/battle/fighter/battlefighterstats.h"
|
||||||
|
|
||||||
#define BATTLE_FIGHTER_ABILITY_COUNT_MAX 8
|
#define BATTLE_FIGHTER_ABILITY_COUNT_MAX 8
|
||||||
|
|
||||||
// An empty status means the slot in BATTLE.fighters is unused.
|
typedef struct battlefighter_s {
|
||||||
typedef enum {
|
|
||||||
BATTLE_FIGHTER_STATUS_NULL,
|
|
||||||
|
|
||||||
BATTLE_FIGHTER_STATUS_NORMAL,
|
|
||||||
BATTLE_FIGHTER_STATUS_DEAD,
|
|
||||||
|
|
||||||
BATTLE_FIGHTER_STATUS_COUNT
|
|
||||||
} battlefighterstatus_t;
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
BATTLE_FIGHTER_TEAM_ALLY,
|
|
||||||
BATTLE_FIGHTER_TEAM_ENEMY,
|
|
||||||
|
|
||||||
BATTLE_FIGHTER_TEAM_COUNT
|
|
||||||
} battlefighterteam_t;
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
BATTLE_FIGHTER_CONTROLLER_PLAYER,
|
|
||||||
BATTLE_FIGHTER_CONTROLLER_AI,
|
|
||||||
|
|
||||||
BATTLE_FIGHTER_CONTROLLER_COUNT
|
|
||||||
} battlefightercontroller_t;
|
|
||||||
|
|
||||||
// Base combat stats, kept separate from the resource pools (health/mp) on
|
|
||||||
// battlefighter_t so that equipment/buffs can later modify them without
|
|
||||||
// touching current health/mp state.
|
|
||||||
typedef struct {
|
|
||||||
uint16_t attack;
|
|
||||||
uint16_t defense;
|
|
||||||
uint16_t magic;
|
|
||||||
uint16_t speed;
|
|
||||||
uint16_t luck;
|
|
||||||
} battlefighterstats_t;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint8_t id;
|
uint8_t id;
|
||||||
battlefighterstatus_t status;
|
battlefighterstatus_t status;
|
||||||
battlefighterteam_t team;
|
battlefighterteam_t team;
|
||||||
@@ -58,7 +27,7 @@ typedef struct {
|
|||||||
uint16_t mpMax;
|
uint16_t mpMax;
|
||||||
|
|
||||||
battlefighterstats_t stats;
|
battlefighterstats_t stats;
|
||||||
battleability_t abilities[BATTLE_FIGHTER_ABILITY_COUNT_MAX];
|
battlemoveid_t abilities[BATTLE_FIGHTER_ABILITY_COUNT_MAX];
|
||||||
} battlefighter_t;
|
} battlefighter_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
/**
|
||||||
|
* 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_FIGHTER_CONTROLLER_NONE,
|
||||||
|
|
||||||
|
BATTLE_FIGHTER_CONTROLLER_PLAYER,
|
||||||
|
BATTLE_FIGHTER_CONTROLLER_AI,
|
||||||
|
|
||||||
|
BATTLE_FIGHTER_CONTROLLER_COUNT
|
||||||
|
} battlefightercontroller_t;
|
||||||
@@ -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 "dusk.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint16_t attack;
|
||||||
|
uint16_t defense;
|
||||||
|
uint16_t magic;
|
||||||
|
uint16_t speed;
|
||||||
|
uint16_t luck;
|
||||||
|
} battlefighterstats_t;
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "dusk.h"
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
BATTLE_FIGHTER_STATUS_NULL,
|
||||||
|
|
||||||
|
BATTLE_FIGHTER_STATUS_NORMAL,
|
||||||
|
BATTLE_FIGHTER_STATUS_DEAD,
|
||||||
|
|
||||||
|
BATTLE_FIGHTER_STATUS_COUNT
|
||||||
|
} battlefighterstatus_t;
|
||||||
+5
-6
@@ -6,12 +6,11 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "error/error.h"
|
#include "dusk.h"
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
BATTLE_ABILITY_NULL,
|
BATTLE_FIGHTER_TEAM_ALLY,
|
||||||
|
BATTLE_FIGHTER_TEAM_ENEMY,
|
||||||
|
|
||||||
BATTLE_ABILITY_FIRE,
|
BATTLE_FIGHTER_TEAM_COUNT
|
||||||
|
} battlefighterteam_t;
|
||||||
BATTLE_ABILITY_COUNT
|
|
||||||
} battleability_t;
|
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
# Copyright (c) 2026 Dominic Masters
|
||||||
|
#
|
||||||
|
# This software is released under the MIT License.
|
||||||
|
# https://opensource.org/licenses/MIT
|
||||||
|
|
||||||
|
# Sources
|
||||||
|
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
||||||
|
PUBLIC
|
||||||
|
battlemove.c
|
||||||
|
)
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "battlemove.h"
|
||||||
|
#include "asset/asset.h"
|
||||||
|
#include "asset/loader/assetloader.h"
|
||||||
|
#include "assert/assert.h"
|
||||||
|
#include "util/memory.h"
|
||||||
|
#include "util/string.h"
|
||||||
|
|
||||||
|
battleability_t BATTLE_MOVES[BATTLE_MOVE_COUNT_MAX];
|
||||||
|
uint8_t BATTLE_MOVE_COUNT;
|
||||||
|
|
||||||
|
errorret_t battleMoveInit(void) {
|
||||||
|
memoryZero(BATTLE_MOVES, sizeof(BATTLE_MOVES));
|
||||||
|
BATTLE_MOVE_COUNT = BATTLE_MOVE_ID_NULL;
|
||||||
|
|
||||||
|
// Get moves JSON.
|
||||||
|
assetentry_t *entry = assetLock(
|
||||||
|
"battle/moves.jsonc", ASSET_LOADER_TYPE_JSON, NULL
|
||||||
|
);
|
||||||
|
errorret_t ret = assetRequireLoaded(entry);
|
||||||
|
if(errorIsNotOk(ret)) {
|
||||||
|
assetUnlockEntry(entry);
|
||||||
|
errorChain(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
yyjson_val *root = yyjson_doc_get_root(entry->data.json);
|
||||||
|
yyjson_val *moves = yyjson_obj_get(root, "moves");
|
||||||
|
yyjson_obj_iter iter = yyjson_obj_iter_with(moves);
|
||||||
|
yyjson_val *key;
|
||||||
|
while((key = yyjson_obj_iter_next(&iter))) {
|
||||||
|
assertTrue(
|
||||||
|
BATTLE_MOVE_COUNT < BATTLE_MOVE_COUNT_MAX,
|
||||||
|
"Too many battle moves defined."
|
||||||
|
);
|
||||||
|
|
||||||
|
yyjson_val *val = yyjson_obj_iter_get_val(key);
|
||||||
|
battlemoveid_t id = BATTLE_MOVE_COUNT++;
|
||||||
|
battleability_t *move = &BATTLE_MOVES[id];
|
||||||
|
|
||||||
|
stringCopy(move->name, yyjson_get_str(key), BATTLE_MOVE_NAME_MAX);
|
||||||
|
|
||||||
|
battletarget_t target = 0;
|
||||||
|
if(yyjson_get_bool(yyjson_obj_get(val, "enemies"))) {
|
||||||
|
target |= BATTLE_TARGET_ENEMIES;
|
||||||
|
}
|
||||||
|
if(yyjson_get_bool(yyjson_obj_get(val, "allies"))) {
|
||||||
|
target |= BATTLE_TARGET_ALLIES;
|
||||||
|
}
|
||||||
|
if(yyjson_get_bool(yyjson_obj_get(val, "multiple"))) {
|
||||||
|
target |= BATTLE_TARGET_MULTIPLE;
|
||||||
|
}
|
||||||
|
if(yyjson_get_bool(yyjson_obj_get(val, "self"))) {
|
||||||
|
target |= BATTLE_TARGET_SELF;
|
||||||
|
}
|
||||||
|
move->target = target;
|
||||||
|
|
||||||
|
const char_t *defaultTarget = yyjson_get_str(
|
||||||
|
yyjson_obj_get(val, "default")
|
||||||
|
);
|
||||||
|
if(defaultTarget != NULL && stringEquals(defaultTarget, "enemy")) {
|
||||||
|
move->targetDefault = BATTLE_TARGET_ENEMIES;
|
||||||
|
} else if(defaultTarget != NULL && stringEquals(defaultTarget, "ally")) {
|
||||||
|
move->targetDefault = BATTLE_TARGET_ALLIES;
|
||||||
|
} else if(defaultTarget != NULL && stringEquals(defaultTarget, "self")) {
|
||||||
|
move->targetDefault = BATTLE_TARGET_SELF;
|
||||||
|
} else {
|
||||||
|
move->targetDefault = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assetUnlockEntry(entry);
|
||||||
|
errorOk();
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "asset/asset.h"
|
||||||
|
#include "battletarget.h"
|
||||||
|
|
||||||
|
#define BATTLE_MOVE_NAME_MAX 16
|
||||||
|
#define BATTLE_MOVE_COUNT_MAX 250
|
||||||
|
|
||||||
|
typedef uint8_t battlemoveid_t;
|
||||||
|
#define BATTLE_MOVE_ID_NULL ((battlemoveid_t)0)
|
||||||
|
|
||||||
|
extern uint8_t BATTLE_MOVE_COUNT;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char_t name[BATTLE_MOVE_NAME_MAX];
|
||||||
|
battletarget_t target;
|
||||||
|
battletarget_t targetDefault;
|
||||||
|
} battleability_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
battlemoveid_t move;
|
||||||
|
uint8_t targetIndex;
|
||||||
|
} battlemoveaction_t;
|
||||||
|
|
||||||
|
extern battleability_t BATTLE_MOVES[BATTLE_MOVE_COUNT_MAX];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the battle move subsystem, loading assets/battle/moves.jsonc.
|
||||||
|
*
|
||||||
|
* @return Any error that occurs.
|
||||||
|
*/
|
||||||
|
errorret_t battleMoveInit(void);
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "dusk.h"
|
||||||
|
|
||||||
|
typedef uint8_t battletarget_t;
|
||||||
|
|
||||||
|
#define BATTLE_TARGET_ENEMIES (1 << 0)
|
||||||
|
#define BATTLE_TARGET_ALLIES (1 << 1)
|
||||||
|
#define BATTLE_TARGET_MULTIPLE (1 << 2)
|
||||||
|
#define BATTLE_TARGET_SELF (1 << 3)
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "battlefighter.h"
|
#include "rpg/battle/fighter/battlefighter.h"
|
||||||
|
|
||||||
#define PARTY_MEMBER_COUNT_MAX 4
|
#define PARTY_MEMBER_COUNT_MAX 4
|
||||||
#define PARTY_ACTIVE_SIZE_MAX 3
|
#define PARTY_ACTIVE_SIZE_MAX 3
|
||||||
@@ -14,12 +14,8 @@
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
battlefighter_t members[PARTY_MEMBER_COUNT_MAX];
|
battlefighter_t members[PARTY_MEMBER_COUNT_MAX];
|
||||||
|
|
||||||
// Maps an active battle slot to the roster member filling it, or
|
|
||||||
// PARTY_ORDER_EMPTY if the slot is unfilled. Only the first
|
|
||||||
// PARTY_ACTIVE_SIZE_MAX of the PARTY_MEMBER_COUNT_MAX roster members
|
|
||||||
// can be in the active lineup at once.
|
|
||||||
uint8_t order[PARTY_ACTIVE_SIZE_MAX];
|
uint8_t order[PARTY_ACTIVE_SIZE_MAX];
|
||||||
|
// TODO: Whether party members are "front" or "back".
|
||||||
} party_t;
|
} party_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -7,6 +7,6 @@ target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
|||||||
PUBLIC
|
PUBLIC
|
||||||
cutscenestartbattle.c
|
cutscenestartbattle.c
|
||||||
cutscenebattlewaitstate.c
|
cutscenebattlewaitstate.c
|
||||||
cutscenebattleforceaction.c
|
cutscenebattleforcemove.c
|
||||||
cutsceneregularbattle.c
|
cutsceneregularbattle.c
|
||||||
)
|
)
|
||||||
|
|||||||
+11
-8
@@ -7,30 +7,33 @@
|
|||||||
|
|
||||||
#include "rpg/cutscene/item/cutsceneitem.h"
|
#include "rpg/cutscene/item/cutsceneitem.h"
|
||||||
|
|
||||||
void cutsceneBattleForceActionStart(
|
// TEMPORARY: hardcoded pending a real moves.jsonc-backed registry lookup.
|
||||||
|
#define BATTLE_MOVE_ID_ATTACK ((battlemoveid_t)1)
|
||||||
|
|
||||||
|
void cutsceneBattleForceMoveStart(
|
||||||
const cutsceneitem_t *item,
|
const cutsceneitem_t *item,
|
||||||
cutsceneitemdata_t *data
|
cutsceneitemdata_t *data
|
||||||
) {
|
) {
|
||||||
battleQueueAction(
|
battleQueueMove(
|
||||||
item->battleForceAction.fighterIndex, BATTLE_ACTION_ATTACK,
|
item->battleForceMove.fighterIndex, BATTLE_MOVE_ID_ATTACK,
|
||||||
item->battleForceAction.targetIndex
|
item->battleForceMove.targetIndex
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool_t cutsceneBattleForceActionUpdate(
|
bool_t cutsceneBattleForceMoveUpdate(
|
||||||
const cutsceneitem_t *item,
|
const cutsceneitem_t *item,
|
||||||
cutsceneitemdata_t *data
|
cutsceneitemdata_t *data
|
||||||
) {
|
) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
errorret_t cutsceneBattleForceActionLoad(
|
errorret_t cutsceneBattleForceMoveLoad(
|
||||||
yyjson_val *itemObj,
|
yyjson_val *itemObj,
|
||||||
cutsceneitem_t *item
|
cutsceneitem_t *item
|
||||||
) {
|
) {
|
||||||
item->battleForceAction.fighterIndex =
|
item->battleForceMove.fighterIndex =
|
||||||
(uint8_t)yyjson_get_int(yyjson_obj_get(itemObj, "fighterIndex"));
|
(uint8_t)yyjson_get_int(yyjson_obj_get(itemObj, "fighterIndex"));
|
||||||
item->battleForceAction.targetIndex =
|
item->battleForceMove.targetIndex =
|
||||||
(uint8_t)yyjson_get_int(yyjson_obj_get(itemObj, "targetIndex"));
|
(uint8_t)yyjson_get_int(yyjson_obj_get(itemObj, "targetIndex"));
|
||||||
|
|
||||||
errorOk();
|
errorOk();
|
||||||
+7
-7
@@ -12,41 +12,41 @@
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t fighterIndex;
|
uint8_t fighterIndex;
|
||||||
uint8_t targetIndex;
|
uint8_t targetIndex;
|
||||||
} cutscenebattleforceaction_t;
|
} cutscenebattleforcemove_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Starts a battle force-action step: immediately queues an attack for the
|
* Starts a battle force-move step: immediately queues an attack for the
|
||||||
* given fighter against the given target, bypassing normal player/AI
|
* given fighter against the given target, bypassing normal player/AI
|
||||||
* selection for that fighter this round.
|
* selection for that fighter this round.
|
||||||
*
|
*
|
||||||
* @param item The cutscene item.
|
* @param item The cutscene item.
|
||||||
* @param data Runtime data storage.
|
* @param data Runtime data storage.
|
||||||
*/
|
*/
|
||||||
void cutsceneBattleForceActionStart(
|
void cutsceneBattleForceMoveStart(
|
||||||
const cutsceneitem_t *item,
|
const cutsceneitem_t *item,
|
||||||
cutsceneitemdata_t *data
|
cutsceneitemdata_t *data
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates a battle force-action step (always completes immediately).
|
* Updates a battle force-move step (always completes immediately).
|
||||||
*
|
*
|
||||||
* @param item The cutscene item.
|
* @param item The cutscene item.
|
||||||
* @param data Runtime data storage.
|
* @param data Runtime data storage.
|
||||||
* @returns true always.
|
* @returns true always.
|
||||||
*/
|
*/
|
||||||
bool_t cutsceneBattleForceActionUpdate(
|
bool_t cutsceneBattleForceMoveUpdate(
|
||||||
const cutsceneitem_t *item,
|
const cutsceneitem_t *item,
|
||||||
cutsceneitemdata_t *data
|
cutsceneitemdata_t *data
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses a BATTLE_FORCE_ACTION cutscene item's JSON fields into item.
|
* Parses a BATTLE_FORCE_MOVE cutscene item's JSON fields into item.
|
||||||
*
|
*
|
||||||
* @param itemObj The item's JSON object.
|
* @param itemObj The item's JSON object.
|
||||||
* @param item Destination item, already zeroed by the caller.
|
* @param item Destination item, already zeroed by the caller.
|
||||||
* @return Error code indicating success or failure of the parse.
|
* @return Error code indicating success or failure of the parse.
|
||||||
*/
|
*/
|
||||||
errorret_t cutsceneBattleForceActionLoad(
|
errorret_t cutsceneBattleForceMoveLoad(
|
||||||
yyjson_val *itemObj,
|
yyjson_val *itemObj,
|
||||||
cutsceneitem_t *item
|
cutsceneitem_t *item
|
||||||
);
|
);
|
||||||
@@ -183,7 +183,7 @@ errorret_t cutsceneStartBattleLoad(
|
|||||||
yyjson_val *abilityVal;
|
yyjson_val *abilityVal;
|
||||||
size_t a = 0;
|
size_t a = 0;
|
||||||
while((abilityVal = yyjson_arr_iter_next(&abilityIter)) != NULL) {
|
while((abilityVal = yyjson_arr_iter_next(&abilityIter)) != NULL) {
|
||||||
battleability_t ability;
|
battlemoveid_t ability;
|
||||||
if(!cutsceneJsonLookupBattleAbility(
|
if(!cutsceneJsonLookupBattleAbility(
|
||||||
yyjson_get_str(abilityVal), &ability
|
yyjson_get_str(abilityVal), &ability
|
||||||
)) {
|
)) {
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ typedef struct {
|
|||||||
battlefighterstats_t stats;
|
battlefighterstats_t stats;
|
||||||
uint16_t healthMax;
|
uint16_t healthMax;
|
||||||
uint16_t mpMax;
|
uint16_t mpMax;
|
||||||
battleability_t abilities[BATTLE_FIGHTER_ABILITY_COUNT_MAX];
|
battlemoveid_t abilities[BATTLE_FIGHTER_ABILITY_COUNT_MAX];
|
||||||
} cutscenestartbattleenemy_t;
|
} cutscenestartbattleenemy_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|||||||
@@ -17,27 +17,7 @@
|
|||||||
cutsceneitemcallbacks_t CUTSCENE_ITEM_CALLBACKS[CUTSCENE_ITEM_TYPE_COUNT] = {
|
cutsceneitemcallbacks_t CUTSCENE_ITEM_CALLBACKS[CUTSCENE_ITEM_TYPE_COUNT] = {
|
||||||
[CUTSCENE_ITEM_TYPE_NULL] = { 0 },
|
[CUTSCENE_ITEM_TYPE_NULL] = { 0 },
|
||||||
|
|
||||||
[CUTSCENE_ITEM_TYPE_TEXT] = {
|
// Control
|
||||||
.init = cutsceneTextStart,
|
|
||||||
.update = cutsceneTextUpdate,
|
|
||||||
.jsonName = "TEXT",
|
|
||||||
.load = cutsceneTextLoad
|
|
||||||
},
|
|
||||||
|
|
||||||
[CUTSCENE_ITEM_TYPE_TEXT_MINI] = {
|
|
||||||
.init = cutsceneTextMiniStart,
|
|
||||||
.update = cutsceneTextMiniUpdate,
|
|
||||||
.jsonName = "TEXT_MINI",
|
|
||||||
.load = cutsceneTextMiniLoad
|
|
||||||
},
|
|
||||||
|
|
||||||
[CUTSCENE_ITEM_TYPE_TEXT_MINI_HIDE] = {
|
|
||||||
.init = cutsceneTextMiniHideStart,
|
|
||||||
.update = cutsceneTextMiniHideUpdate,
|
|
||||||
.jsonName = "TEXT_MINI_HIDE",
|
|
||||||
.load = cutsceneTextMiniHideLoad
|
|
||||||
},
|
|
||||||
|
|
||||||
[CUTSCENE_ITEM_TYPE_CALLBACK] = {
|
[CUTSCENE_ITEM_TYPE_CALLBACK] = {
|
||||||
.init = cutsceneCallbackStart,
|
.init = cutsceneCallbackStart,
|
||||||
.update = cutsceneCallbackUpdate
|
.update = cutsceneCallbackUpdate
|
||||||
@@ -57,25 +37,11 @@ cutsceneitemcallbacks_t CUTSCENE_ITEM_CALLBACKS[CUTSCENE_ITEM_TYPE_COUNT] = {
|
|||||||
.load = cutsceneCutsceneLoad
|
.load = cutsceneCutsceneLoad
|
||||||
},
|
},
|
||||||
|
|
||||||
[CUTSCENE_ITEM_TYPE_ENTITY_TELEPORT] = {
|
[CUTSCENE_ITEM_TYPE_INSERT] = {
|
||||||
.init = cutsceneEntityTeleportStart,
|
.init = cutsceneInsertStart,
|
||||||
.update = cutsceneEntityTeleportUpdate,
|
.update = cutsceneInsertUpdate,
|
||||||
.jsonName = "ENTITY_TELEPORT",
|
.jsonName = "INSERT",
|
||||||
.load = cutsceneEntityTeleportLoad
|
.load = cutsceneInsertLoad
|
||||||
},
|
|
||||||
|
|
||||||
[CUTSCENE_ITEM_TYPE_ENTITY_WALK_TO] = {
|
|
||||||
.init = cutsceneEntityWalkToStart,
|
|
||||||
.update = cutsceneEntityWalkToUpdate,
|
|
||||||
.jsonName = "ENTITY_WALK_TO",
|
|
||||||
.load = cutsceneEntityWalkToLoad
|
|
||||||
},
|
|
||||||
|
|
||||||
[CUTSCENE_ITEM_TYPE_FADE] = {
|
|
||||||
.init = cutsceneFadeStart,
|
|
||||||
.update = cutsceneFadeUpdate,
|
|
||||||
.jsonName = "FADE",
|
|
||||||
.load = cutsceneFadeLoad
|
|
||||||
},
|
},
|
||||||
|
|
||||||
[CUTSCENE_ITEM_TYPE_SET_PAUSE] = {
|
[CUTSCENE_ITEM_TYPE_SET_PAUSE] = {
|
||||||
@@ -90,122 +56,6 @@ cutsceneitemcallbacks_t CUTSCENE_ITEM_CALLBACKS[CUTSCENE_ITEM_TYPE_COUNT] = {
|
|||||||
.update = cutsceneConcurrentUpdate
|
.update = cutsceneConcurrentUpdate
|
||||||
},
|
},
|
||||||
|
|
||||||
[CUTSCENE_ITEM_TYPE_ITEM_GIVE] = {
|
|
||||||
.init = cutsceneItemGiveStart,
|
|
||||||
.update = cutsceneItemGiveUpdate,
|
|
||||||
.jsonName = "ITEM_GIVE",
|
|
||||||
.load = cutsceneItemGiveLoad
|
|
||||||
},
|
|
||||||
|
|
||||||
[CUTSCENE_ITEM_TYPE_ENTITY_REMOVE] = {
|
|
||||||
.init = cutsceneEntityRemoveStart,
|
|
||||||
.update = cutsceneEntityRemoveUpdate,
|
|
||||||
.jsonName = "ENTITY_REMOVE",
|
|
||||||
.load = cutsceneEntityRemoveLoad
|
|
||||||
},
|
|
||||||
|
|
||||||
[CUTSCENE_ITEM_TYPE_ENTITY_ADD] = {
|
|
||||||
.init = cutsceneEntityAddStart,
|
|
||||||
.update = cutsceneEntityAddUpdate,
|
|
||||||
.jsonName = "ENTITY_ADD",
|
|
||||||
.load = cutsceneEntityAddLoad
|
|
||||||
},
|
|
||||||
|
|
||||||
[CUTSCENE_ITEM_TYPE_ENTITY_TURN] = {
|
|
||||||
.init = cutsceneEntityTurnStart,
|
|
||||||
.update = cutsceneEntityTurnUpdate,
|
|
||||||
.jsonName = "ENTITY_TURN",
|
|
||||||
.load = cutsceneEntityTurnLoad
|
|
||||||
},
|
|
||||||
|
|
||||||
[CUTSCENE_ITEM_TYPE_ENTITY_WALK_TO_ENTITY] = {
|
|
||||||
.init = cutsceneEntityWalkToEntityStart,
|
|
||||||
.update = cutsceneEntityWalkToEntityUpdate,
|
|
||||||
.jsonName = "ENTITY_WALK_TO_ENTITY",
|
|
||||||
.load = cutsceneEntityWalkToEntityLoad
|
|
||||||
},
|
|
||||||
|
|
||||||
[CUTSCENE_ITEM_TYPE_MAP_AREA_ADD] = {
|
|
||||||
.init = cutsceneMapAreaAddStart,
|
|
||||||
.update = cutsceneMapAreaAddUpdate
|
|
||||||
},
|
|
||||||
|
|
||||||
[CUTSCENE_ITEM_TYPE_MAP_AREA_REMOVE] = {
|
|
||||||
.init = cutsceneMapAreaRemoveStart,
|
|
||||||
.update = cutsceneMapAreaRemoveUpdate,
|
|
||||||
.jsonName = "MAP_AREA_REMOVE",
|
|
||||||
.load = cutsceneMapAreaRemoveLoad
|
|
||||||
},
|
|
||||||
|
|
||||||
[CUTSCENE_ITEM_TYPE_MAP_AREA_WAIT] = {
|
|
||||||
.init = cutsceneMapAreaWaitStart,
|
|
||||||
.update = cutsceneMapAreaWaitUpdate,
|
|
||||||
.jsonName = "MAP_AREA_WAIT",
|
|
||||||
.load = cutsceneMapAreaWaitLoad
|
|
||||||
},
|
|
||||||
|
|
||||||
[CUTSCENE_ITEM_TYPE_START_BATTLE] = {
|
|
||||||
.init = cutsceneStartBattleStart,
|
|
||||||
.update = cutsceneStartBattleUpdate,
|
|
||||||
.jsonName = "START_BATTLE",
|
|
||||||
.load = cutsceneStartBattleLoad
|
|
||||||
},
|
|
||||||
|
|
||||||
[CUTSCENE_ITEM_TYPE_EMOJI] = {
|
|
||||||
.init = cutsceneEmojiStart,
|
|
||||||
.update = cutsceneEmojiUpdate,
|
|
||||||
.jsonName = "EMOJI",
|
|
||||||
.load = cutsceneEmojiLoad
|
|
||||||
},
|
|
||||||
|
|
||||||
[CUTSCENE_ITEM_TYPE_SHAKE] = {
|
|
||||||
.init = cutsceneShakeStart,
|
|
||||||
.update = cutsceneShakeUpdate,
|
|
||||||
.jsonName = "SHAKE",
|
|
||||||
.load = cutsceneShakeLoad
|
|
||||||
},
|
|
||||||
|
|
||||||
[CUTSCENE_ITEM_TYPE_BATTLE_WAIT_STATE] = {
|
|
||||||
.update = cutsceneBattleWaitStateUpdate,
|
|
||||||
.jsonName = "BATTLE_WAIT_STATE",
|
|
||||||
.load = cutsceneBattleWaitStateLoad
|
|
||||||
},
|
|
||||||
|
|
||||||
[CUTSCENE_ITEM_TYPE_BATTLE_FORCE_ACTION] = {
|
|
||||||
.init = cutsceneBattleForceActionStart,
|
|
||||||
.update = cutsceneBattleForceActionUpdate,
|
|
||||||
.jsonName = "BATTLE_FORCE_ACTION",
|
|
||||||
.load = cutsceneBattleForceActionLoad
|
|
||||||
},
|
|
||||||
|
|
||||||
[CUTSCENE_ITEM_TYPE_MODAL] = {
|
|
||||||
.init = cutsceneModalStart,
|
|
||||||
.update = cutsceneModalUpdate,
|
|
||||||
.jsonName = "MODAL",
|
|
||||||
.load = cutsceneModalLoad
|
|
||||||
},
|
|
||||||
|
|
||||||
[CUTSCENE_ITEM_TYPE_MODAL_OPTIONS_MARKERS] = {
|
|
||||||
.init = cutsceneModalOptionsMarkersStart,
|
|
||||||
.update = cutsceneModalOptionsMarkersUpdate,
|
|
||||||
.jsonName = "MODAL_OPTIONS_MARKERS",
|
|
||||||
.load = cutsceneModalOptionsMarkersLoad
|
|
||||||
},
|
|
||||||
|
|
||||||
[CUTSCENE_ITEM_TYPE_MODAL_CLOSE] = {
|
|
||||||
.init = cutsceneModalCloseStart,
|
|
||||||
.update = cutsceneModalCloseUpdate,
|
|
||||||
.jsonName = "MODAL_CLOSE",
|
|
||||||
.load = cutsceneItemLoadNoop
|
|
||||||
},
|
|
||||||
|
|
||||||
[CUTSCENE_ITEM_TYPE_PRINT] = {
|
|
||||||
.init = cutscenePrintStart,
|
|
||||||
.update = cutscenePrintUpdate,
|
|
||||||
.jsonName = "PRINT",
|
|
||||||
.load = cutscenePrintLoad
|
|
||||||
},
|
|
||||||
|
|
||||||
[CUTSCENE_ITEM_TYPE_MARKER] = {
|
[CUTSCENE_ITEM_TYPE_MARKER] = {
|
||||||
.init = cutsceneMarkerStart,
|
.init = cutsceneMarkerStart,
|
||||||
.update = cutsceneMarkerUpdate,
|
.update = cutsceneMarkerUpdate,
|
||||||
@@ -234,6 +84,194 @@ cutsceneitemcallbacks_t CUTSCENE_ITEM_CALLBACKS[CUTSCENE_ITEM_TYPE_COUNT] = {
|
|||||||
.load = cutsceneSceneLoad
|
.load = cutsceneSceneLoad
|
||||||
},
|
},
|
||||||
|
|
||||||
|
[CUTSCENE_ITEM_TYPE_IDLE] = {
|
||||||
|
.update = cutsceneIdleUpdate,
|
||||||
|
.jsonName = "IDLE",
|
||||||
|
.load = cutsceneItemLoadNoop
|
||||||
|
},
|
||||||
|
|
||||||
|
// Entity
|
||||||
|
[CUTSCENE_ITEM_TYPE_ENTITY_TELEPORT] = {
|
||||||
|
.init = cutsceneEntityTeleportStart,
|
||||||
|
.update = cutsceneEntityTeleportUpdate,
|
||||||
|
.jsonName = "ENTITY_TELEPORT",
|
||||||
|
.load = cutsceneEntityTeleportLoad
|
||||||
|
},
|
||||||
|
|
||||||
|
[CUTSCENE_ITEM_TYPE_ENTITY_WALK_TO] = {
|
||||||
|
.init = cutsceneEntityWalkToStart,
|
||||||
|
.update = cutsceneEntityWalkToUpdate,
|
||||||
|
.jsonName = "ENTITY_WALK_TO",
|
||||||
|
.load = cutsceneEntityWalkToLoad
|
||||||
|
},
|
||||||
|
|
||||||
|
[CUTSCENE_ITEM_TYPE_ENTITY_WALK_TO_ENTITY] = {
|
||||||
|
.init = cutsceneEntityWalkToEntityStart,
|
||||||
|
.update = cutsceneEntityWalkToEntityUpdate,
|
||||||
|
.jsonName = "ENTITY_WALK_TO_ENTITY",
|
||||||
|
.load = cutsceneEntityWalkToEntityLoad
|
||||||
|
},
|
||||||
|
|
||||||
|
[CUTSCENE_ITEM_TYPE_ENTITY_REMOVE] = {
|
||||||
|
.init = cutsceneEntityRemoveStart,
|
||||||
|
.update = cutsceneEntityRemoveUpdate,
|
||||||
|
.jsonName = "ENTITY_REMOVE",
|
||||||
|
.load = cutsceneEntityRemoveLoad
|
||||||
|
},
|
||||||
|
|
||||||
|
[CUTSCENE_ITEM_TYPE_ENTITY_ADD] = {
|
||||||
|
.init = cutsceneEntityAddStart,
|
||||||
|
.update = cutsceneEntityAddUpdate,
|
||||||
|
.jsonName = "ENTITY_ADD",
|
||||||
|
.load = cutsceneEntityAddLoad
|
||||||
|
},
|
||||||
|
|
||||||
|
[CUTSCENE_ITEM_TYPE_ENTITY_TURN] = {
|
||||||
|
.init = cutsceneEntityTurnStart,
|
||||||
|
.update = cutsceneEntityTurnUpdate,
|
||||||
|
.jsonName = "ENTITY_TURN",
|
||||||
|
.load = cutsceneEntityTurnLoad
|
||||||
|
},
|
||||||
|
|
||||||
|
// UI
|
||||||
|
[CUTSCENE_ITEM_TYPE_TEXT] = {
|
||||||
|
.init = cutsceneTextStart,
|
||||||
|
.update = cutsceneTextUpdate,
|
||||||
|
.jsonName = "TEXT",
|
||||||
|
.load = cutsceneTextLoad
|
||||||
|
},
|
||||||
|
|
||||||
|
[CUTSCENE_ITEM_TYPE_TEXT_MINI] = {
|
||||||
|
.init = cutsceneTextMiniStart,
|
||||||
|
.update = cutsceneTextMiniUpdate,
|
||||||
|
.jsonName = "TEXT_MINI",
|
||||||
|
.load = cutsceneTextMiniLoad
|
||||||
|
},
|
||||||
|
|
||||||
|
[CUTSCENE_ITEM_TYPE_TEXT_MINI_HIDE] = {
|
||||||
|
.init = cutsceneTextMiniHideStart,
|
||||||
|
.update = cutsceneTextMiniHideUpdate,
|
||||||
|
.jsonName = "TEXT_MINI_HIDE",
|
||||||
|
.load = cutsceneTextMiniHideLoad
|
||||||
|
},
|
||||||
|
|
||||||
|
[CUTSCENE_ITEM_TYPE_PRINT] = {
|
||||||
|
.init = cutscenePrintStart,
|
||||||
|
.update = cutscenePrintUpdate,
|
||||||
|
.jsonName = "PRINT",
|
||||||
|
.load = cutscenePrintLoad
|
||||||
|
},
|
||||||
|
|
||||||
|
[CUTSCENE_ITEM_TYPE_FADE] = {
|
||||||
|
.init = cutsceneFadeStart,
|
||||||
|
.update = cutsceneFadeUpdate,
|
||||||
|
.jsonName = "FADE",
|
||||||
|
.load = cutsceneFadeLoad
|
||||||
|
},
|
||||||
|
|
||||||
|
[CUTSCENE_ITEM_TYPE_EMOJI] = {
|
||||||
|
.init = cutsceneEmojiStart,
|
||||||
|
.update = cutsceneEmojiUpdate,
|
||||||
|
.jsonName = "EMOJI",
|
||||||
|
.load = cutsceneEmojiLoad
|
||||||
|
},
|
||||||
|
|
||||||
|
[CUTSCENE_ITEM_TYPE_SHAKE] = {
|
||||||
|
.init = cutsceneShakeStart,
|
||||||
|
.update = cutsceneShakeUpdate,
|
||||||
|
.jsonName = "SHAKE",
|
||||||
|
.load = cutsceneShakeLoad
|
||||||
|
},
|
||||||
|
|
||||||
|
[CUTSCENE_ITEM_TYPE_MODAL] = {
|
||||||
|
.init = cutsceneModalStart,
|
||||||
|
.update = cutsceneModalUpdate,
|
||||||
|
.jsonName = "MODAL",
|
||||||
|
.load = cutsceneModalLoad
|
||||||
|
},
|
||||||
|
|
||||||
|
[CUTSCENE_ITEM_TYPE_MODAL_OPTIONS_MARKERS] = {
|
||||||
|
.init = cutsceneModalOptionsMarkersStart,
|
||||||
|
.update = cutsceneModalOptionsMarkersUpdate,
|
||||||
|
.jsonName = "MODAL_OPTIONS_MARKERS",
|
||||||
|
.load = cutsceneModalOptionsMarkersLoad
|
||||||
|
},
|
||||||
|
|
||||||
|
[CUTSCENE_ITEM_TYPE_MODAL_CLOSE] = {
|
||||||
|
.init = cutsceneModalCloseStart,
|
||||||
|
.update = cutsceneModalCloseUpdate,
|
||||||
|
.jsonName = "MODAL_CLOSE",
|
||||||
|
.load = cutsceneItemLoadNoop
|
||||||
|
},
|
||||||
|
|
||||||
|
[CUTSCENE_ITEM_TYPE_KEYBOARD] = {
|
||||||
|
.init = cutsceneKeyboardStart,
|
||||||
|
.update = cutsceneKeyboardUpdate
|
||||||
|
},
|
||||||
|
|
||||||
|
[CUTSCENE_ITEM_TYPE_UI_SHOW] = {
|
||||||
|
.init = cutsceneUIShowStart,
|
||||||
|
.update = cutsceneUIShowUpdate,
|
||||||
|
.jsonName = "UI_SHOW",
|
||||||
|
.load = cutsceneUIShowLoad
|
||||||
|
},
|
||||||
|
|
||||||
|
// Item
|
||||||
|
[CUTSCENE_ITEM_TYPE_ITEM_GIVE] = {
|
||||||
|
.init = cutsceneItemGiveStart,
|
||||||
|
.update = cutsceneItemGiveUpdate,
|
||||||
|
.jsonName = "ITEM_GIVE",
|
||||||
|
.load = cutsceneItemGiveLoad
|
||||||
|
},
|
||||||
|
|
||||||
|
// Map area
|
||||||
|
[CUTSCENE_ITEM_TYPE_MAP_AREA_ADD] = {
|
||||||
|
.init = cutsceneMapAreaAddStart,
|
||||||
|
.update = cutsceneMapAreaAddUpdate
|
||||||
|
},
|
||||||
|
|
||||||
|
[CUTSCENE_ITEM_TYPE_MAP_AREA_REMOVE] = {
|
||||||
|
.init = cutsceneMapAreaRemoveStart,
|
||||||
|
.update = cutsceneMapAreaRemoveUpdate,
|
||||||
|
.jsonName = "MAP_AREA_REMOVE",
|
||||||
|
.load = cutsceneMapAreaRemoveLoad
|
||||||
|
},
|
||||||
|
|
||||||
|
[CUTSCENE_ITEM_TYPE_MAP_AREA_WAIT] = {
|
||||||
|
.init = cutsceneMapAreaWaitStart,
|
||||||
|
.update = cutsceneMapAreaWaitUpdate,
|
||||||
|
.jsonName = "MAP_AREA_WAIT",
|
||||||
|
.load = cutsceneMapAreaWaitLoad
|
||||||
|
},
|
||||||
|
|
||||||
|
// Battle
|
||||||
|
[CUTSCENE_ITEM_TYPE_START_BATTLE] = {
|
||||||
|
.init = cutsceneStartBattleStart,
|
||||||
|
.update = cutsceneStartBattleUpdate,
|
||||||
|
.jsonName = "START_BATTLE",
|
||||||
|
.load = cutsceneStartBattleLoad
|
||||||
|
},
|
||||||
|
|
||||||
|
[CUTSCENE_ITEM_TYPE_BATTLE_WAIT_STATE] = {
|
||||||
|
.update = cutsceneBattleWaitStateUpdate,
|
||||||
|
.jsonName = "BATTLE_WAIT_STATE",
|
||||||
|
.load = cutsceneBattleWaitStateLoad
|
||||||
|
},
|
||||||
|
|
||||||
|
[CUTSCENE_ITEM_TYPE_BATTLE_FORCE_MOVE] = {
|
||||||
|
.init = cutsceneBattleForceMoveStart,
|
||||||
|
.update = cutsceneBattleForceMoveUpdate,
|
||||||
|
.jsonName = "BATTLE_FORCE_MOVE",
|
||||||
|
.load = cutsceneBattleForceMoveLoad
|
||||||
|
},
|
||||||
|
|
||||||
|
[CUTSCENE_ITEM_TYPE_REGULAR_BATTLE] = {
|
||||||
|
.update = cutsceneRegularBattleUpdate,
|
||||||
|
.jsonName = "REGULAR_BATTLE",
|
||||||
|
.load = cutsceneItemLoadNoop
|
||||||
|
},
|
||||||
|
|
||||||
|
// Save
|
||||||
[CUTSCENE_ITEM_TYPE_SAVE_DEVICE_CHECK] = {
|
[CUTSCENE_ITEM_TYPE_SAVE_DEVICE_CHECK] = {
|
||||||
.init = cutsceneSaveDeviceCheckStart,
|
.init = cutsceneSaveDeviceCheckStart,
|
||||||
.update = cutsceneSaveDeviceCheckUpdate,
|
.update = cutsceneSaveDeviceCheckUpdate,
|
||||||
@@ -248,11 +286,7 @@ cutsceneitemcallbacks_t CUTSCENE_ITEM_CALLBACKS[CUTSCENE_ITEM_TYPE_COUNT] = {
|
|||||||
.load = cutsceneSaveLoadAllSlotsLoad
|
.load = cutsceneSaveLoadAllSlotsLoad
|
||||||
},
|
},
|
||||||
|
|
||||||
[CUTSCENE_ITEM_TYPE_KEYBOARD] = {
|
// Audio
|
||||||
.init = cutsceneKeyboardStart,
|
|
||||||
.update = cutsceneKeyboardUpdate
|
|
||||||
},
|
|
||||||
|
|
||||||
[CUTSCENE_ITEM_TYPE_AUDIO_PLAY] = {
|
[CUTSCENE_ITEM_TYPE_AUDIO_PLAY] = {
|
||||||
.init = cutsceneAudioPlayStart,
|
.init = cutsceneAudioPlayStart,
|
||||||
.update = cutsceneAudioPlayUpdate,
|
.update = cutsceneAudioPlayUpdate,
|
||||||
@@ -315,32 +349,7 @@ cutsceneitemcallbacks_t CUTSCENE_ITEM_CALLBACKS[CUTSCENE_ITEM_TYPE_COUNT] = {
|
|||||||
.load = cutsceneAudioSetLoad
|
.load = cutsceneAudioSetLoad
|
||||||
},
|
},
|
||||||
|
|
||||||
[CUTSCENE_ITEM_TYPE_IDLE] = {
|
// Story
|
||||||
.update = cutsceneIdleUpdate,
|
|
||||||
.jsonName = "IDLE",
|
|
||||||
.load = cutsceneItemLoadNoop
|
|
||||||
},
|
|
||||||
|
|
||||||
[CUTSCENE_ITEM_TYPE_UI_SHOW] = {
|
|
||||||
.init = cutsceneUIShowStart,
|
|
||||||
.update = cutsceneUIShowUpdate,
|
|
||||||
.jsonName = "UI_SHOW",
|
|
||||||
.load = cutsceneUIShowLoad
|
|
||||||
},
|
|
||||||
|
|
||||||
[CUTSCENE_ITEM_TYPE_REGULAR_BATTLE] = {
|
|
||||||
.update = cutsceneRegularBattleUpdate,
|
|
||||||
.jsonName = "REGULAR_BATTLE",
|
|
||||||
.load = cutsceneItemLoadNoop
|
|
||||||
},
|
|
||||||
|
|
||||||
[CUTSCENE_ITEM_TYPE_INSERT] = {
|
|
||||||
.init = cutsceneInsertStart,
|
|
||||||
.update = cutsceneInsertUpdate,
|
|
||||||
.jsonName = "INSERT",
|
|
||||||
.load = cutsceneInsertLoad
|
|
||||||
},
|
|
||||||
|
|
||||||
[CUTSCENE_ITEM_TYPE_STORY_SET_FLAG] = {
|
[CUTSCENE_ITEM_TYPE_STORY_SET_FLAG] = {
|
||||||
.init = cutsceneStorySetFlagStart,
|
.init = cutsceneStorySetFlagStart,
|
||||||
.update = cutsceneStorySetFlagUpdate,
|
.update = cutsceneStorySetFlagUpdate,
|
||||||
@@ -506,8 +515,9 @@ void cutsceneInsertResolveAndSplice(const char_t *name) {
|
|||||||
// nothing needs to keep the doc itself resident past the parse.
|
// nothing needs to keep the doc itself resident past the parse.
|
||||||
cutsceneitem_t items[CUTSCENE_INSERT_ITEMS_MAX];
|
cutsceneitem_t items[CUTSCENE_INSERT_ITEMS_MAX];
|
||||||
cutscene_t scene = { .items = items };
|
cutscene_t scene = { .items = items };
|
||||||
errorret_t parseResult =
|
errorret_t parseResult = cutsceneParseDoc(
|
||||||
cutsceneParseDoc(entry->data.json, &scene, items, CUTSCENE_INSERT_ITEMS_MAX);
|
entry->data.json, &scene, items, CUTSCENE_INSERT_ITEMS_MAX
|
||||||
|
);
|
||||||
assetUnlockEntry(entry);
|
assetUnlockEntry(entry);
|
||||||
if(errorIsNotOk(parseResult)) {
|
if(errorIsNotOk(parseResult)) {
|
||||||
errorCatch(errorPrint(parseResult));
|
errorCatch(errorPrint(parseResult));
|
||||||
|
|||||||
@@ -42,7 +42,7 @@
|
|||||||
#include "maparea/cutscenemapareawait.h"
|
#include "maparea/cutscenemapareawait.h"
|
||||||
#include "battle/cutscenestartbattle.h"
|
#include "battle/cutscenestartbattle.h"
|
||||||
#include "battle/cutscenebattlewaitstate.h"
|
#include "battle/cutscenebattlewaitstate.h"
|
||||||
#include "battle/cutscenebattleforceaction.h"
|
#include "battle/cutscenebattleforcemove.h"
|
||||||
#include "battle/cutsceneregularbattle.h"
|
#include "battle/cutsceneregularbattle.h"
|
||||||
#include "save/cutscenesavedevicecheck.h"
|
#include "save/cutscenesavedevicecheck.h"
|
||||||
#include "save/cutscenesaveloadallslots.h"
|
#include "save/cutscenesaveloadallslots.h"
|
||||||
@@ -120,7 +120,7 @@ struct cutsceneitem_s {
|
|||||||
cutsceneemoji_t emoji;
|
cutsceneemoji_t emoji;
|
||||||
cutsceneshake_t shake;
|
cutsceneshake_t shake;
|
||||||
cutscenebattlewaitstate_t battleWaitState;
|
cutscenebattlewaitstate_t battleWaitState;
|
||||||
cutscenebattleforceaction_t battleForceAction;
|
cutscenebattleforcemove_t battleForceMove;
|
||||||
cutscenemodal_t modal;
|
cutscenemodal_t modal;
|
||||||
cutscenemodaloptionsmarkers_t modalOptionsMarkers;
|
cutscenemodaloptionsmarkers_t modalOptionsMarkers;
|
||||||
cutsceneprint_t print;
|
cutsceneprint_t print;
|
||||||
|
|||||||
@@ -16,41 +16,60 @@ typedef union cutsceneitemdata_u cutsceneitemdata_t;
|
|||||||
typedef enum {
|
typedef enum {
|
||||||
CUTSCENE_ITEM_TYPE_NULL,
|
CUTSCENE_ITEM_TYPE_NULL,
|
||||||
|
|
||||||
CUTSCENE_ITEM_TYPE_TEXT,
|
// Control
|
||||||
CUTSCENE_ITEM_TYPE_TEXT_MINI,
|
|
||||||
CUTSCENE_ITEM_TYPE_TEXT_MINI_HIDE,
|
|
||||||
CUTSCENE_ITEM_TYPE_CALLBACK,
|
CUTSCENE_ITEM_TYPE_CALLBACK,
|
||||||
CUTSCENE_ITEM_TYPE_WAIT,
|
CUTSCENE_ITEM_TYPE_WAIT,
|
||||||
CUTSCENE_ITEM_TYPE_CUTSCENE,
|
CUTSCENE_ITEM_TYPE_CUTSCENE,
|
||||||
CUTSCENE_ITEM_TYPE_ENTITY_TELEPORT,
|
CUTSCENE_ITEM_TYPE_INSERT,
|
||||||
CUTSCENE_ITEM_TYPE_ENTITY_WALK_TO,
|
|
||||||
CUTSCENE_ITEM_TYPE_FADE,
|
|
||||||
CUTSCENE_ITEM_TYPE_SET_PAUSE,
|
CUTSCENE_ITEM_TYPE_SET_PAUSE,
|
||||||
CUTSCENE_ITEM_TYPE_CONCURRENT,
|
CUTSCENE_ITEM_TYPE_CONCURRENT,
|
||||||
CUTSCENE_ITEM_TYPE_ITEM_GIVE,
|
|
||||||
CUTSCENE_ITEM_TYPE_ENTITY_REMOVE,
|
|
||||||
CUTSCENE_ITEM_TYPE_ENTITY_ADD,
|
|
||||||
CUTSCENE_ITEM_TYPE_ENTITY_TURN,
|
|
||||||
CUTSCENE_ITEM_TYPE_ENTITY_WALK_TO_ENTITY,
|
|
||||||
CUTSCENE_ITEM_TYPE_MAP_AREA_ADD,
|
|
||||||
CUTSCENE_ITEM_TYPE_MAP_AREA_REMOVE,
|
|
||||||
CUTSCENE_ITEM_TYPE_MAP_AREA_WAIT,
|
|
||||||
CUTSCENE_ITEM_TYPE_START_BATTLE,
|
|
||||||
CUTSCENE_ITEM_TYPE_EMOJI,
|
|
||||||
CUTSCENE_ITEM_TYPE_SHAKE,
|
|
||||||
CUTSCENE_ITEM_TYPE_BATTLE_WAIT_STATE,
|
|
||||||
CUTSCENE_ITEM_TYPE_BATTLE_FORCE_ACTION,
|
|
||||||
CUTSCENE_ITEM_TYPE_MODAL,
|
|
||||||
CUTSCENE_ITEM_TYPE_MODAL_OPTIONS_MARKERS,
|
|
||||||
CUTSCENE_ITEM_TYPE_MODAL_CLOSE,
|
|
||||||
CUTSCENE_ITEM_TYPE_PRINT,
|
|
||||||
CUTSCENE_ITEM_TYPE_MARKER,
|
CUTSCENE_ITEM_TYPE_MARKER,
|
||||||
CUTSCENE_ITEM_TYPE_RESTART,
|
CUTSCENE_ITEM_TYPE_RESTART,
|
||||||
CUTSCENE_ITEM_TYPE_QUIT_GAME,
|
CUTSCENE_ITEM_TYPE_QUIT_GAME,
|
||||||
CUTSCENE_ITEM_TYPE_SCENE,
|
CUTSCENE_ITEM_TYPE_SCENE,
|
||||||
|
CUTSCENE_ITEM_TYPE_IDLE,
|
||||||
|
|
||||||
|
// Entity
|
||||||
|
CUTSCENE_ITEM_TYPE_ENTITY_TELEPORT,
|
||||||
|
CUTSCENE_ITEM_TYPE_ENTITY_WALK_TO,
|
||||||
|
CUTSCENE_ITEM_TYPE_ENTITY_WALK_TO_ENTITY,
|
||||||
|
CUTSCENE_ITEM_TYPE_ENTITY_REMOVE,
|
||||||
|
CUTSCENE_ITEM_TYPE_ENTITY_ADD,
|
||||||
|
CUTSCENE_ITEM_TYPE_ENTITY_TURN,
|
||||||
|
|
||||||
|
// UI
|
||||||
|
CUTSCENE_ITEM_TYPE_TEXT,
|
||||||
|
CUTSCENE_ITEM_TYPE_TEXT_MINI,
|
||||||
|
CUTSCENE_ITEM_TYPE_TEXT_MINI_HIDE,
|
||||||
|
CUTSCENE_ITEM_TYPE_PRINT,
|
||||||
|
CUTSCENE_ITEM_TYPE_FADE,
|
||||||
|
CUTSCENE_ITEM_TYPE_EMOJI,
|
||||||
|
CUTSCENE_ITEM_TYPE_SHAKE,
|
||||||
|
CUTSCENE_ITEM_TYPE_MODAL,
|
||||||
|
CUTSCENE_ITEM_TYPE_MODAL_OPTIONS_MARKERS,
|
||||||
|
CUTSCENE_ITEM_TYPE_MODAL_CLOSE,
|
||||||
|
CUTSCENE_ITEM_TYPE_KEYBOARD,
|
||||||
|
CUTSCENE_ITEM_TYPE_UI_SHOW,
|
||||||
|
|
||||||
|
// Item
|
||||||
|
CUTSCENE_ITEM_TYPE_ITEM_GIVE,
|
||||||
|
|
||||||
|
// Map area
|
||||||
|
CUTSCENE_ITEM_TYPE_MAP_AREA_ADD,
|
||||||
|
CUTSCENE_ITEM_TYPE_MAP_AREA_REMOVE,
|
||||||
|
CUTSCENE_ITEM_TYPE_MAP_AREA_WAIT,
|
||||||
|
|
||||||
|
// Battle
|
||||||
|
CUTSCENE_ITEM_TYPE_START_BATTLE,
|
||||||
|
CUTSCENE_ITEM_TYPE_BATTLE_WAIT_STATE,
|
||||||
|
CUTSCENE_ITEM_TYPE_BATTLE_FORCE_MOVE,
|
||||||
|
CUTSCENE_ITEM_TYPE_REGULAR_BATTLE,
|
||||||
|
|
||||||
|
// Save
|
||||||
CUTSCENE_ITEM_TYPE_SAVE_DEVICE_CHECK,
|
CUTSCENE_ITEM_TYPE_SAVE_DEVICE_CHECK,
|
||||||
CUTSCENE_ITEM_TYPE_SAVE_LOAD_ALL_SLOTS,
|
CUTSCENE_ITEM_TYPE_SAVE_LOAD_ALL_SLOTS,
|
||||||
CUTSCENE_ITEM_TYPE_KEYBOARD,
|
|
||||||
|
// Audio
|
||||||
CUTSCENE_ITEM_TYPE_AUDIO_PLAY,
|
CUTSCENE_ITEM_TYPE_AUDIO_PLAY,
|
||||||
CUTSCENE_ITEM_TYPE_AUDIO_STOP,
|
CUTSCENE_ITEM_TYPE_AUDIO_STOP,
|
||||||
CUTSCENE_ITEM_TYPE_AUDIO_PAUSE,
|
CUTSCENE_ITEM_TYPE_AUDIO_PAUSE,
|
||||||
@@ -60,10 +79,8 @@ typedef enum {
|
|||||||
CUTSCENE_ITEM_TYPE_AUDIO_SET_PAN,
|
CUTSCENE_ITEM_TYPE_AUDIO_SET_PAN,
|
||||||
CUTSCENE_ITEM_TYPE_AUDIO_SET_LOOP,
|
CUTSCENE_ITEM_TYPE_AUDIO_SET_LOOP,
|
||||||
CUTSCENE_ITEM_TYPE_AUDIO_SET,
|
CUTSCENE_ITEM_TYPE_AUDIO_SET,
|
||||||
CUTSCENE_ITEM_TYPE_IDLE,
|
|
||||||
CUTSCENE_ITEM_TYPE_UI_SHOW,
|
// Story
|
||||||
CUTSCENE_ITEM_TYPE_REGULAR_BATTLE,
|
|
||||||
CUTSCENE_ITEM_TYPE_INSERT,
|
|
||||||
CUTSCENE_ITEM_TYPE_STORY_SET_FLAG,
|
CUTSCENE_ITEM_TYPE_STORY_SET_FLAG,
|
||||||
CUTSCENE_ITEM_TYPE_STORY_WAIT_FLAG,
|
CUTSCENE_ITEM_TYPE_STORY_WAIT_FLAG,
|
||||||
|
|
||||||
|
|||||||
@@ -8,8 +8,12 @@
|
|||||||
#include "cutscenejsonbattleability.h"
|
#include "cutscenejsonbattleability.h"
|
||||||
#include "cutscenejsonenum.h"
|
#include "cutscenejsonenum.h"
|
||||||
|
|
||||||
|
// TEMPORARY: hardcoded pending a real moves.jsonc-backed registry lookup
|
||||||
|
// (see BATTLE_MOVE_COUNT).
|
||||||
|
#define BATTLE_MOVE_ID_FIRE ((battlemoveid_t)2)
|
||||||
|
|
||||||
static const cutscenejsonenumentry_t CUTSCENE_JSON_BATTLE_ABILITY_TABLE[] = {
|
static const cutscenejsonenumentry_t CUTSCENE_JSON_BATTLE_ABILITY_TABLE[] = {
|
||||||
{ "FIRE", BATTLE_ABILITY_FIRE },
|
{ "FIRE", BATTLE_MOVE_ID_FIRE },
|
||||||
};
|
};
|
||||||
#define CUTSCENE_JSON_BATTLE_ABILITY_TABLE_COUNT \
|
#define CUTSCENE_JSON_BATTLE_ABILITY_TABLE_COUNT \
|
||||||
(sizeof(CUTSCENE_JSON_BATTLE_ABILITY_TABLE) / \
|
(sizeof(CUTSCENE_JSON_BATTLE_ABILITY_TABLE) / \
|
||||||
@@ -17,7 +21,7 @@ static const cutscenejsonenumentry_t CUTSCENE_JSON_BATTLE_ABILITY_TABLE[] = {
|
|||||||
|
|
||||||
bool_t cutsceneJsonLookupBattleAbility(
|
bool_t cutsceneJsonLookupBattleAbility(
|
||||||
const char_t *name,
|
const char_t *name,
|
||||||
battleability_t *out
|
battlemoveid_t *out
|
||||||
) {
|
) {
|
||||||
int32_t value;
|
int32_t value;
|
||||||
if(!cutsceneJsonLookupEnumInsensitive(
|
if(!cutsceneJsonLookupEnumInsensitive(
|
||||||
@@ -26,6 +30,6 @@ bool_t cutsceneJsonLookupBattleAbility(
|
|||||||
)) {
|
)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
*out = (battleability_t)value;
|
*out = (battlemoveid_t)value;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,16 +7,16 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "dusk.h"
|
#include "dusk.h"
|
||||||
#include "rpg/battle/battleability.h"
|
#include "rpg/battle/move/battlemove.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Looks up name (case-insensitively) against the battle ability table.
|
* Looks up name (case-insensitively) against the battle ability table.
|
||||||
*
|
*
|
||||||
* @param name Name to search for.
|
* @param name Name to search for.
|
||||||
* @param out Set to the matching ability on success.
|
* @param out Set to the matching move id on success.
|
||||||
* @return true if a matching entry was found, false otherwise.
|
* @return true if a matching entry was found, false otherwise.
|
||||||
*/
|
*/
|
||||||
bool_t cutsceneJsonLookupBattleAbility(
|
bool_t cutsceneJsonLookupBattleAbility(
|
||||||
const char_t *name,
|
const char_t *name,
|
||||||
battleability_t *out
|
battlemoveid_t *out
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ ENTITY_GLOBAL_CALLBACK(3) {
|
|||||||
|
|
||||||
ENTITY_GLOBAL_CALLBACK(4) {
|
ENTITY_GLOBAL_CALLBACK(4) {
|
||||||
create->entity->interact.type = ENTITY_INTERACT_CUTSCENE_NAME;
|
create->entity->interact.type = ENTITY_INTERACT_CUTSCENE_NAME;
|
||||||
create->entity->interact.data.cutsceneName = "battletest";
|
create->entity->interact.data.cutsceneName = "cutscenes/battletest.jsonc";
|
||||||
}
|
}
|
||||||
|
|
||||||
static const entityglobaldef_t ENTITY_GLOBAL_LIST[] = {
|
static const entityglobaldef_t ENTITY_GLOBAL_LIST[] = {
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
#include "rpg/item/item.h"
|
#include "rpg/item/item.h"
|
||||||
#include "rpg/item/backpack.h"
|
#include "rpg/item/backpack.h"
|
||||||
#include "rpg/battle/party.h"
|
#include "rpg/battle/party.h"
|
||||||
|
#include "rpg/battle/move/battlemove.h"
|
||||||
#include "save/save.h"
|
#include "save/save.h"
|
||||||
#include "ui/rpg/textbox/uitextboxminilist.h"
|
#include "ui/rpg/textbox/uitextboxminilist.h"
|
||||||
#include "time/time.h"
|
#include "time/time.h"
|
||||||
@@ -30,6 +31,7 @@ errorret_t rpgInit(void) {
|
|||||||
|
|
||||||
errorChain(storyInit());
|
errorChain(storyInit());
|
||||||
errorChain(itemInit());
|
errorChain(itemInit());
|
||||||
|
errorChain(battleMoveInit());
|
||||||
backpackInit();
|
backpackInit();
|
||||||
partyInit();
|
partyInit();
|
||||||
cutsceneSystemInit();
|
cutsceneSystemInit();
|
||||||
|
|||||||
+23
-119
@@ -9,7 +9,10 @@
|
|||||||
#include "rpg/battle/battle.h"
|
#include "rpg/battle/battle.h"
|
||||||
#include "rpg/cutscene/cutscenesystem.h"
|
#include "rpg/cutscene/cutscenesystem.h"
|
||||||
|
|
||||||
// Fighter slots as added by test_battleCutsceneForceActionOverridesTarget:
|
// TEMPORARY: hardcoded pending a real moves.jsonc-backed registry lookup.
|
||||||
|
#define BATTLE_MOVE_ID_ATTACK ((battlemoveid_t)1)
|
||||||
|
|
||||||
|
// Fighter slots as added by test_battleCutsceneForceMoveOverridesTarget:
|
||||||
// 0 = allyA, 1 = allyB, 2 = enemy.
|
// 0 = allyA, 1 = allyB, 2 = enemy.
|
||||||
static cutsceneitem_t CUTSCENE_TEST_SCRATCH_ITEMS[] = {
|
static cutsceneitem_t CUTSCENE_TEST_SCRATCH_ITEMS[] = {
|
||||||
// Waiting BEFORE pausing is the correct order: pausing first would
|
// Waiting BEFORE pausing is the correct order: pausing first would
|
||||||
@@ -22,8 +25,8 @@ static cutsceneitem_t CUTSCENE_TEST_SCRATCH_ITEMS[] = {
|
|||||||
{ .type = CUTSCENE_ITEM_TYPE_SET_PAUSE, .setPause = CUTSCENE_PAUSE_BATTLE },
|
{ .type = CUTSCENE_ITEM_TYPE_SET_PAUSE, .setPause = CUTSCENE_PAUSE_BATTLE },
|
||||||
// enemy (slot 2) forced onto allyA (slot 0)
|
// enemy (slot 2) forced onto allyA (slot 0)
|
||||||
{
|
{
|
||||||
.type = CUTSCENE_ITEM_TYPE_BATTLE_FORCE_ACTION,
|
.type = CUTSCENE_ITEM_TYPE_BATTLE_FORCE_MOVE,
|
||||||
.battleForceAction = { .fighterIndex = 2, .targetIndex = 0 }
|
.battleForceMove = { .fighterIndex = 2, .targetIndex = 0 }
|
||||||
},
|
},
|
||||||
{ .type = CUTSCENE_ITEM_TYPE_SET_PAUSE, .setPause = CUTSCENE_PAUSE_NONE }
|
{ .type = CUTSCENE_ITEM_TYPE_SET_PAUSE, .setPause = CUTSCENE_PAUSE_NONE }
|
||||||
};
|
};
|
||||||
@@ -101,13 +104,13 @@ static void test_battlePlayerSelectionAdvancesAndSkipsDecidedFighters(
|
|||||||
assert_int_equal(BATTLE.state, BATTLE_STATE_PLAYER_SELECTION);
|
assert_int_equal(BATTLE.state, BATTLE_STATE_PLAYER_SELECTION);
|
||||||
assert_ptr_equal(battleGetCurrentFighter(), ally1);
|
assert_ptr_equal(battleGetCurrentFighter(), ally1);
|
||||||
|
|
||||||
// A forced action (as a scripted-battle cutscene item would push) marks
|
// A forced move (as a scripted-battle cutscene item would push) marks
|
||||||
// ally2 as already decided, so PLAYER_SELECTION must skip it.
|
// ally2 as already decided, so PLAYER_SELECTION must skip it.
|
||||||
battleQueueAction(ally2->id, BATTLE_ACTION_ATTACK, enemy->id);
|
battleQueueMove(ally2->id, BATTLE_MOVE_ID_ATTACK, enemy->id);
|
||||||
|
|
||||||
battlePlayerAttack(enemy->id);
|
battlePlayerAttack(enemy->id);
|
||||||
assert_int_equal(BATTLE.actions[ally1->id].type, BATTLE_ACTION_ATTACK);
|
assert_int_equal(BATTLE.moves[ally1->id].move, BATTLE_MOVE_ID_ATTACK);
|
||||||
assert_int_equal(BATTLE.actions[ally1->id].targetIndex, enemy->id);
|
assert_int_equal(BATTLE.moves[ally1->id].targetIndex, enemy->id);
|
||||||
|
|
||||||
// ally2 already had a decision queued, and enemy is AI-controlled, so
|
// ally2 already had a decision queued, and enemy is AI-controlled, so
|
||||||
// there's nothing left for PLAYER_SELECTION -- it should have moved on.
|
// there's nothing left for PLAYER_SELECTION -- it should have moved on.
|
||||||
@@ -134,8 +137,8 @@ static void test_battleAiSelectionAutoQueuesUndecidedAiFighters(void **state) {
|
|||||||
|
|
||||||
battleUpdate();// AI_SELECTION auto-decides for enemy
|
battleUpdate();// AI_SELECTION auto-decides for enemy
|
||||||
assert_int_equal(BATTLE.state, BATTLE_STATE_MOVES_EXECUTING);
|
assert_int_equal(BATTLE.state, BATTLE_STATE_MOVES_EXECUTING);
|
||||||
assert_int_equal(BATTLE.actions[enemy->id].type, BATTLE_ACTION_ATTACK);
|
assert_int_equal(BATTLE.moves[enemy->id].move, BATTLE_MOVE_ID_ATTACK);
|
||||||
assert_int_equal(BATTLE.actions[enemy->id].targetIndex, ally->id);
|
assert_int_equal(BATTLE.moves[enemy->id].targetIndex, ally->id);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_battleMovesExecutingResolvesInSpeedOrderAndFizzles(
|
static void test_battleMovesExecutingResolvesInSpeedOrderAndFizzles(
|
||||||
@@ -278,107 +281,12 @@ static void test_battleFleeUnavailableIsIgnored(void **state) {
|
|||||||
assert_int_equal(BATTLE.result, BATTLE_RESULT_NONE);
|
assert_int_equal(BATTLE.result, BATTLE_RESULT_NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint8_t stateChangedCount;
|
|
||||||
static battlestate_t stateChangedLog[32][2];
|
|
||||||
|
|
||||||
static void recordStateChanged(
|
|
||||||
const battlestate_t previous,
|
|
||||||
const battlestate_t next
|
|
||||||
) {
|
|
||||||
if(stateChangedCount >= 32) return;
|
|
||||||
stateChangedLog[stateChangedCount][0] = previous;
|
|
||||||
stateChangedLog[stateChangedCount][1] = next;
|
|
||||||
stateChangedCount++;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void test_battleOnStateChangedFiresAcrossFullRound(void **state) {
|
|
||||||
|
|
||||||
|
|
||||||
battleInit();
|
|
||||||
stateChangedCount = 0;
|
|
||||||
BATTLE.onStateChanged = recordStateChanged;
|
|
||||||
|
|
||||||
addFighter(
|
|
||||||
BATTLE_FIGHTER_TEAM_ALLY, BATTLE_FIGHTER_CONTROLLER_PLAYER, 1, 0, 10, 100
|
|
||||||
);
|
|
||||||
battlefighter_t *enemy = addFighter(
|
|
||||||
BATTLE_FIGHTER_TEAM_ENEMY, BATTLE_FIGHTER_CONTROLLER_AI, 1, 0, 5, 100
|
|
||||||
);
|
|
||||||
|
|
||||||
battleStart(BATTLE_ENCOUNTER_REGULAR, true);// fires NONE -> OPENING
|
|
||||||
battleUpdate();// OPENING -> PRE_ROUND
|
|
||||||
battleUpdate();// PRE_ROUND -> PLAYER_SELECTION
|
|
||||||
battlePlayerAttack(enemy->id);// PLAYER_SELECTION -> AI_SELECTION
|
|
||||||
battleUpdate();// AI_SELECTION -> MOVES_EXECUTING
|
|
||||||
battleUpdate();// MOVES_EXECUTING: ally's attack resolves (still executing)
|
|
||||||
battleUpdate();// MOVES_EXECUTING: enemy's attack resolves (still executing)
|
|
||||||
battleUpdate();// both slots processed -> POST_ROUND
|
|
||||||
battleUpdate();// POST_ROUND -> PRE_ROUND, round advances
|
|
||||||
|
|
||||||
assert_int_equal(stateChangedLog[0][0], BATTLE_STATE_NONE);
|
|
||||||
assert_int_equal(stateChangedLog[0][1], BATTLE_STATE_OPENING);
|
|
||||||
assert_int_equal(stateChangedLog[1][1], BATTLE_STATE_PRE_ROUND);
|
|
||||||
assert_int_equal(stateChangedLog[2][1], BATTLE_STATE_PLAYER_SELECTION);
|
|
||||||
assert_int_equal(stateChangedLog[3][1], BATTLE_STATE_AI_SELECTION);
|
|
||||||
assert_int_equal(stateChangedLog[4][1], BATTLE_STATE_MOVES_EXECUTING);
|
|
||||||
assert_int_equal(stateChangedLog[5][1], BATTLE_STATE_POST_ROUND);
|
|
||||||
assert_int_equal(stateChangedLog[6][1], BATTLE_STATE_PRE_ROUND);
|
|
||||||
|
|
||||||
BATTLE.onStateChanged = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint8_t actionDecidedCount;
|
|
||||||
|
|
||||||
static void recordActionDecided(
|
|
||||||
const battlefighter_t *fighter,
|
|
||||||
const battleaction_t *action
|
|
||||||
) {
|
|
||||||
actionDecidedCount++;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void test_battleOnActionDecidedFiresPerFighterRegardlessOfSource(
|
|
||||||
void **state
|
|
||||||
) {
|
|
||||||
|
|
||||||
|
|
||||||
battleInit();
|
|
||||||
actionDecidedCount = 0;
|
|
||||||
BATTLE.onActionDecided = recordActionDecided;
|
|
||||||
|
|
||||||
battlefighter_t *ally1 = addFighter(
|
|
||||||
BATTLE_FIGHTER_TEAM_ALLY, BATTLE_FIGHTER_CONTROLLER_PLAYER, 1, 0, 10, 100
|
|
||||||
);
|
|
||||||
battlefighter_t *ally2 = addFighter(
|
|
||||||
BATTLE_FIGHTER_TEAM_ALLY, BATTLE_FIGHTER_CONTROLLER_PLAYER, 1, 0, 9, 100
|
|
||||||
);
|
|
||||||
battlefighter_t *enemy = addFighter(
|
|
||||||
BATTLE_FIGHTER_TEAM_ENEMY, BATTLE_FIGHTER_CONTROLLER_AI, 1, 0, 5, 100
|
|
||||||
);
|
|
||||||
|
|
||||||
battleStart(BATTLE_ENCOUNTER_REGULAR, true);
|
|
||||||
battleUpdate();// OPENING -> PRE_ROUND
|
|
||||||
battleUpdate();// PRE_ROUND -> PLAYER_SELECTION
|
|
||||||
|
|
||||||
// A forced action, as CUTSCENE_BATTLE_FORCE_ACTION would push, counts too.
|
|
||||||
battleQueueAction(ally2->id, BATTLE_ACTION_ATTACK, enemy->id);
|
|
||||||
assert_int_equal(actionDecidedCount, 1);
|
|
||||||
|
|
||||||
battlePlayerAttack(enemy->id);// ally1's real decision
|
|
||||||
assert_int_equal(actionDecidedCount, 2);
|
|
||||||
assert_int_equal(BATTLE.state, BATTLE_STATE_AI_SELECTION);
|
|
||||||
|
|
||||||
battleUpdate();// AI_SELECTION decides for enemy
|
|
||||||
assert_int_equal(actionDecidedCount, 3);
|
|
||||||
|
|
||||||
BATTLE.onActionDecided = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Exercises CUTSCENE_BATTLE_WAIT_STATE + CUTSCENE_SET_PAUSE(BATTLE) +
|
// Exercises CUTSCENE_BATTLE_WAIT_STATE + CUTSCENE_SET_PAUSE(BATTLE) +
|
||||||
// CUTSCENE_BATTLE_FORCE_ACTION together, driving the cutscene and battle
|
// CUTSCENE_BATTLE_FORCE_MOVE together, driving the cutscene and battle
|
||||||
// systems side by side the way rpg.c's main loop does, to prove a
|
// systems side by side the way rpg.c's main loop does, to prove a
|
||||||
// partially-scripted round actually works end-to-end (not just that each
|
// partially-scripted round actually works end-to-end (not just that each
|
||||||
// item type compiles).
|
// item type compiles).
|
||||||
static void test_battleCutsceneForceActionOverridesTarget(void **state) {
|
static void test_battleCutsceneForceMoveOverridesTarget(void **state) {
|
||||||
|
|
||||||
|
|
||||||
battleInit();
|
battleInit();
|
||||||
@@ -411,22 +319,22 @@ static void test_battleCutsceneForceActionOverridesTarget(void **state) {
|
|||||||
assert_int_equal(BATTLE.state, BATTLE_STATE_PRE_ROUND);
|
assert_int_equal(BATTLE.state, BATTLE_STATE_PRE_ROUND);
|
||||||
assert_true(CUTSCENE_SYSTEM.pause & CUTSCENE_PAUSE_BATTLE);
|
assert_true(CUTSCENE_SYSTEM.pause & CUTSCENE_PAUSE_BATTLE);
|
||||||
|
|
||||||
cutsceneSystemUpdate();// SET_PAUSE done -> FORCE_ACTION queues enemy's move
|
cutsceneSystemUpdate();// SET_PAUSE done -> FORCE_MOVE queues enemy's move
|
||||||
battleUpdate();// still paused: no-op
|
battleUpdate();// still paused: no-op
|
||||||
|
|
||||||
assert_int_equal(BATTLE.actions[enemy->id].type, BATTLE_ACTION_ATTACK);
|
assert_int_equal(BATTLE.moves[enemy->id].move, BATTLE_MOVE_ID_ATTACK);
|
||||||
assert_int_equal(BATTLE.actions[enemy->id].targetIndex, allyA->id);
|
assert_int_equal(BATTLE.moves[enemy->id].targetIndex, allyA->id);
|
||||||
assert_int_equal(BATTLE.state, BATTLE_STATE_PRE_ROUND);// still frozen
|
assert_int_equal(BATTLE.state, BATTLE_STATE_PRE_ROUND);// still frozen
|
||||||
|
|
||||||
cutsceneSystemUpdate();// FORCE_ACTION done -> SET_PAUSE(NONE) lifts it
|
cutsceneSystemUpdate();// FORCE_MOVE done -> SET_PAUSE(NONE) lifts it
|
||||||
battleUpdate();// unpaused: PRE_ROUND -> PLAYER_SELECTION, allyA first
|
battleUpdate();// unpaused: PRE_ROUND -> PLAYER_SELECTION, allyA first
|
||||||
|
|
||||||
assert_false(CUTSCENE_SYSTEM.pause & CUTSCENE_PAUSE_BATTLE);
|
assert_false(CUTSCENE_SYSTEM.pause & CUTSCENE_PAUSE_BATTLE);
|
||||||
assert_int_equal(BATTLE.state, BATTLE_STATE_PLAYER_SELECTION);
|
assert_int_equal(BATTLE.state, BATTLE_STATE_PLAYER_SELECTION);
|
||||||
assert_ptr_equal(battleGetCurrentFighter(), allyA);
|
assert_ptr_equal(battleGetCurrentFighter(), allyA);
|
||||||
// The forced action from three frames ago survived untouched.
|
// The forced move from three frames ago survived untouched.
|
||||||
assert_int_equal(BATTLE.actions[enemy->id].type, BATTLE_ACTION_ATTACK);
|
assert_int_equal(BATTLE.moves[enemy->id].move, BATTLE_MOVE_ID_ATTACK);
|
||||||
assert_int_equal(BATTLE.actions[enemy->id].targetIndex, allyA->id);
|
assert_int_equal(BATTLE.moves[enemy->id].targetIndex, allyA->id);
|
||||||
|
|
||||||
battlePlayerAttack(enemy->id);// allyA -> AI_SELECTION would be next...
|
battlePlayerAttack(enemy->id);// allyA -> AI_SELECTION would be next...
|
||||||
assert_ptr_equal(battleGetCurrentFighter(), allyB);
|
assert_ptr_equal(battleGetCurrentFighter(), allyB);
|
||||||
@@ -437,7 +345,7 @@ static void test_battleCutsceneForceActionOverridesTarget(void **state) {
|
|||||||
// AI_SELECTION: enemy already decided, skipped -> MOVES_EXECUTING
|
// AI_SELECTION: enemy already decided, skipped -> MOVES_EXECUTING
|
||||||
battleUpdate();
|
battleUpdate();
|
||||||
// untouched
|
// untouched
|
||||||
assert_int_equal(BATTLE.actions[enemy->id].targetIndex, allyA->id);
|
assert_int_equal(BATTLE.moves[enemy->id].targetIndex, allyA->id);
|
||||||
|
|
||||||
battleUpdate();// allyA attacks enemy
|
battleUpdate();// allyA attacks enemy
|
||||||
battleUpdate();// allyB attacks enemy
|
battleUpdate();// allyB attacks enemy
|
||||||
@@ -458,11 +366,7 @@ int main(int argc, char** argv) {
|
|||||||
cmocka_unit_test(test_battleLossEndsInStateEnded),
|
cmocka_unit_test(test_battleLossEndsInStateEnded),
|
||||||
cmocka_unit_test(test_battleFleeEndsInStateEndedImmediately),
|
cmocka_unit_test(test_battleFleeEndsInStateEndedImmediately),
|
||||||
cmocka_unit_test(test_battleFleeUnavailableIsIgnored),
|
cmocka_unit_test(test_battleFleeUnavailableIsIgnored),
|
||||||
cmocka_unit_test(test_battleOnStateChangedFiresAcrossFullRound),
|
cmocka_unit_test(test_battleCutsceneForceMoveOverridesTarget),
|
||||||
cmocka_unit_test(
|
|
||||||
test_battleOnActionDecidedFiresPerFighterRegardlessOfSource
|
|
||||||
),
|
|
||||||
cmocka_unit_test(test_battleCutsceneForceActionOverridesTarget),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return cmocka_run_group_tests(tests, NULL, NULL);
|
return cmocka_run_group_tests(tests, NULL, NULL);
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ import zipfile
|
|||||||
import zlib
|
import zlib
|
||||||
import io
|
import io
|
||||||
|
|
||||||
MAGIC = b'DSK2'
|
MAGIC = b'DSK'
|
||||||
VERSION = 2
|
VERSION = 2
|
||||||
HEADER_FORMAT = '<4sIII'
|
HEADER_FORMAT = '<4sIII'
|
||||||
HEADER_SIZE = struct.calcsize(HEADER_FORMAT)
|
HEADER_SIZE = struct.calcsize(HEADER_FORMAT)
|
||||||
|
|||||||
Reference in New Issue
Block a user