Key-based party roster, show party member names in battle UI
- party.jsonc's "members" is now a key/value object (e.g. "hero", "companion") instead of an array - partyInit seeds party_t.keys alongside members, and partyGetMemberIndexByKey/partyGetMemberKey do the lookups. Cutscene items (PARTY_ADD_MEMBER/PARTY_REMOVE_MEMBER/ PARTY_HEAL_MEMBER) now take a "key" JSON field, resolved to a roster index at load time, instead of a raw index. - Battle UI shows who's acting: uibattlemenu.c draws the current fighter's party key above the action menu, and uibattlehud.c draws each ally fighter's key as an extra line above their HP/MP. Co-Authored-By: Claude Sonnet 5 <[email protected]>
This commit is contained in:
+7
-4
@@ -1,13 +1,16 @@
|
|||||||
{
|
{
|
||||||
// Starting party roster, loaded by partyInit into a fresh save slot.
|
// Starting party roster, loaded by partyInit into a fresh save slot.
|
||||||
"members": [
|
// Each key is a stable identifier cutscene content can reference
|
||||||
{
|
// directly (see PARTY_ADD_MEMBER/PARTY_REMOVE_MEMBER/PARTY_HEAL_MEMBER's
|
||||||
|
// "key" field) instead of a fragile positional index.
|
||||||
|
"members": {
|
||||||
|
"hero": {
|
||||||
"attack": 10, "defense": 5, "magic": 0, "speed": 10, "luck": 0,
|
"attack": 10, "defense": 5, "magic": 0, "speed": 10, "luck": 0,
|
||||||
"healthMax": 30, "mpMax": 10
|
"healthMax": 30, "mpMax": 10
|
||||||
},
|
},
|
||||||
{
|
"companion": {
|
||||||
"attack": 8, "defense": 6, "magic": 4, "speed": 8, "luck": 1,
|
"attack": 8, "defense": 6, "magic": 4, "speed": 8, "luck": 1,
|
||||||
"healthMax": 25, "mpMax": 15
|
"healthMax": 25, "mpMax": 15
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
#include "party.h"
|
#include "party.h"
|
||||||
#include "assert/assert.h"
|
#include "assert/assert.h"
|
||||||
#include "util/memory.h"
|
#include "util/memory.h"
|
||||||
|
#include "util/string.h"
|
||||||
#include "save/save.h"
|
#include "save/save.h"
|
||||||
#include "asset/asset.h"
|
#include "asset/asset.h"
|
||||||
#include "asset/loader/assetloader.h"
|
#include "asset/loader/assetloader.h"
|
||||||
@@ -66,12 +67,12 @@ errorret_t partyInit(party_t *party) {
|
|||||||
|
|
||||||
yyjson_val *root = yyjson_doc_get_root(entry->data.json);
|
yyjson_val *root = yyjson_doc_get_root(entry->data.json);
|
||||||
yyjson_val *members = yyjson_obj_get(root, "members");
|
yyjson_val *members = yyjson_obj_get(root, "members");
|
||||||
if(!yyjson_is_arr(members)) {
|
if(!yyjson_is_obj(members)) {
|
||||||
assetUnlockEntry(entry);
|
assetUnlockEntry(entry);
|
||||||
errorThrow("party.jsonc: missing/invalid 'members' array");
|
errorThrow("party.jsonc: missing/invalid 'members' object");
|
||||||
}
|
}
|
||||||
|
|
||||||
const size_t memberCount = yyjson_arr_size(members);
|
const size_t memberCount = yyjson_obj_size(members);
|
||||||
if(memberCount > PARTY_MEMBER_COUNT_MAX) {
|
if(memberCount > PARTY_MEMBER_COUNT_MAX) {
|
||||||
assetUnlockEntry(entry);
|
assetUnlockEntry(entry);
|
||||||
errorThrow(
|
errorThrow(
|
||||||
@@ -80,9 +81,21 @@ errorret_t partyInit(party_t *party) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t idx, max;
|
uint8_t idx = 0;
|
||||||
|
yyjson_val *key;
|
||||||
yyjson_val *memberObj;
|
yyjson_val *memberObj;
|
||||||
yyjson_arr_foreach(members, idx, max, memberObj) {
|
yyjson_obj_iter iter = yyjson_obj_iter_with(members);
|
||||||
|
while((key = yyjson_obj_iter_next(&iter))) {
|
||||||
|
memberObj = yyjson_obj_iter_get_val(key);
|
||||||
|
|
||||||
|
if(yyjson_get_len(key) >= PARTY_KEY_LENGTH_MAX) {
|
||||||
|
assetUnlockEntry(entry);
|
||||||
|
errorThrow(
|
||||||
|
"party.jsonc: member key '%s' exceeds PARTY_KEY_LENGTH_MAX (%u)",
|
||||||
|
yyjson_get_str(key), PARTY_KEY_LENGTH_MAX
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
battlefighterstats_t stats;
|
battlefighterstats_t stats;
|
||||||
errorret_t statsResult = partyParseStats(memberObj, &stats);
|
errorret_t statsResult = partyParseStats(memberObj, &stats);
|
||||||
if(errorIsNotOk(statsResult)) {
|
if(errorIsNotOk(statsResult)) {
|
||||||
@@ -90,12 +103,16 @@ errorret_t partyInit(party_t *party) {
|
|||||||
errorChain(statsResult);
|
errorChain(statsResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
stringCopy(party->keys[idx], yyjson_get_str(key), PARTY_KEY_LENGTH_MAX - 1);
|
||||||
|
|
||||||
battlefighter_t *member = &party->members[idx];
|
battlefighter_t *member = &party->members[idx];
|
||||||
member->id = (uint8_t)idx;
|
member->id = idx;
|
||||||
battleFighterInit(
|
battleFighterInit(
|
||||||
member, BATTLE_FIGHTER_TEAM_ALLY, BATTLE_FIGHTER_CONTROLLER_PLAYER,
|
member, BATTLE_FIGHTER_TEAM_ALLY, BATTLE_FIGHTER_CONTROLLER_PLAYER,
|
||||||
stats
|
stats
|
||||||
);
|
);
|
||||||
|
|
||||||
|
idx++;
|
||||||
}
|
}
|
||||||
|
|
||||||
assetUnlockEntry(entry);
|
assetUnlockEntry(entry);
|
||||||
@@ -110,6 +127,22 @@ errorret_t partyInit(party_t *party) {
|
|||||||
errorOk();
|
errorOk();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint8_t partyGetMemberIndexByKey(const char_t *key) {
|
||||||
|
assertNotNull(key, "Key cannot be NULL");
|
||||||
|
|
||||||
|
const party_t *party = &SAVE.slot.party;
|
||||||
|
for(uint8_t i = 0; i < PARTY_MEMBER_COUNT_MAX; i++) {
|
||||||
|
if(stringEquals(party->keys[i], key)) return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return PARTY_MEMBER_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char_t *partyGetMemberKey(const uint8_t memberIndex) {
|
||||||
|
assertTrue(memberIndex < PARTY_MEMBER_COUNT_MAX, "Invalid party member index");
|
||||||
|
return SAVE.slot.party.keys[memberIndex];
|
||||||
|
}
|
||||||
|
|
||||||
bool_t partyIsMemberActive(const uint8_t memberIndex) {
|
bool_t partyIsMemberActive(const uint8_t memberIndex) {
|
||||||
assertTrue(memberIndex < PARTY_MEMBER_COUNT_MAX, "Invalid party member index");
|
assertTrue(memberIndex < PARTY_MEMBER_COUNT_MAX, "Invalid party member index");
|
||||||
|
|
||||||
|
|||||||
+35
-16
@@ -9,36 +9,55 @@
|
|||||||
#include "rpg/battle/fighter/battlefighter.h"
|
#include "rpg/battle/fighter/battlefighter.h"
|
||||||
#include "yyjson.h"
|
#include "yyjson.h"
|
||||||
|
|
||||||
#define PARTY_MEMBER_COUNT_MAX 4
|
#define PARTY_MEMBER_COUNT_MAX 10
|
||||||
#define PARTY_ACTIVE_SIZE_MAX 3
|
#define PARTY_ACTIVE_SIZE_MAX 4
|
||||||
|
#define PARTY_KEY_LENGTH_MAX 32
|
||||||
#define PARTY_ORDER_EMPTY 0xFF
|
#define PARTY_ORDER_EMPTY 0xFF
|
||||||
|
#define PARTY_MEMBER_NOT_FOUND 0xFF
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
// Every member party.jsonc defines always exists here (seeded by
|
|
||||||
// partyInit), regardless of whether it's currently active - order (not
|
|
||||||
// this array, and not a member's status) is what determines who's
|
|
||||||
// currently in the party.
|
|
||||||
battlefighter_t members[PARTY_MEMBER_COUNT_MAX];
|
battlefighter_t members[PARTY_MEMBER_COUNT_MAX];
|
||||||
|
char_t keys[PARTY_MEMBER_COUNT_MAX][PARTY_KEY_LENGTH_MAX];
|
||||||
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;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes party with an empty order, then seeds every roster slot
|
* Initializes party with an empty order, then seeds every roster slot
|
||||||
* directly from party.jsonc's "members" array (index i of the array fills
|
* directly from party.jsonc's "members" object (each key/value pair fills
|
||||||
* members[i] via partyParseStats/battleFighterInit) - unlike
|
* the next members[]/keys[] slot in the object's iteration order, key
|
||||||
* partyAddMember, this never touches order itself except for one
|
* copied into keys[] and value parsed via partyParseStats/
|
||||||
* placeholder default: if party.jsonc defines at least one member,
|
* battleFighterInit) - unlike partyAddMember, this never touches order
|
||||||
* order[0] is set to 0 (member 0 starts active in the first party
|
* itself except for one placeholder default: if party.jsonc defines at
|
||||||
* position). Replace this default once there's a real starting-party/
|
* least one member, order[0] is set to 0 (the first member starts active
|
||||||
* character-creation flow.
|
* in the first party position). Replace this default once there's a real
|
||||||
|
* starting-party/character-creation flow.
|
||||||
*
|
*
|
||||||
* @param party The party to initialize.
|
* @param party The party to initialize.
|
||||||
* @return Error if party.jsonc fails to load/parse, or if it defines more
|
* @return Error if party.jsonc fails to load/parse, defines more members
|
||||||
* members than PARTY_MEMBER_COUNT_MAX has room for.
|
* than PARTY_MEMBER_COUNT_MAX has room for, or a key exceeds
|
||||||
|
* PARTY_KEY_LENGTH_MAX.
|
||||||
*/
|
*/
|
||||||
errorret_t partyInit(party_t *party);
|
errorret_t partyInit(party_t *party);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Looks up a roster member's index by its party.jsonc key (see
|
||||||
|
* party_t.keys).
|
||||||
|
*
|
||||||
|
* @param key The member's key to search for.
|
||||||
|
* @return The matching roster index, or PARTY_MEMBER_NOT_FOUND if no
|
||||||
|
* member has that key.
|
||||||
|
*/
|
||||||
|
uint8_t partyGetMemberIndexByKey(const char_t *key);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a roster member's party.jsonc key by index (see party_t.keys).
|
||||||
|
*
|
||||||
|
* @param memberIndex The roster member index to query.
|
||||||
|
* @return The member's key - "" if memberIndex is past however many
|
||||||
|
* members party.jsonc actually defines.
|
||||||
|
*/
|
||||||
|
const char_t *partyGetMemberKey(const uint8_t memberIndex);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses a set of base combat stats (attack/defense/magic/speed/luck/
|
* Parses a set of base combat stats (attack/defense/magic/speed/luck/
|
||||||
* healthMax/mpMax) out of a JSON object. Every field is required - there
|
* healthMax/mpMax) out of a JSON object. Every field is required - there
|
||||||
|
|||||||
@@ -27,13 +27,16 @@ errorret_t cutscenePartyAddMemberLoad(
|
|||||||
yyjson_val *itemObj,
|
yyjson_val *itemObj,
|
||||||
cutsceneitem_t *item
|
cutsceneitem_t *item
|
||||||
) {
|
) {
|
||||||
const int32_t memberIndex = cutsceneJsonGetInt(itemObj, "memberIndex", -1);
|
char_t key[PARTY_KEY_LENGTH_MAX];
|
||||||
if(memberIndex < 0 || memberIndex >= PARTY_MEMBER_COUNT_MAX) {
|
if(!cutsceneJsonCopyString(itemObj, "key", NULL, key, PARTY_KEY_LENGTH_MAX)) {
|
||||||
errorThrow(
|
errorThrow("Cutscene item (PARTY_ADD_MEMBER): missing/invalid 'key'");
|
||||||
"Cutscene item (PARTY_ADD_MEMBER): invalid/missing 'memberIndex'"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
item->partyAddMember.memberIndex = (uint8_t)memberIndex;
|
|
||||||
|
const uint8_t memberIndex = partyGetMemberIndexByKey(key);
|
||||||
|
if(memberIndex == PARTY_MEMBER_NOT_FOUND) {
|
||||||
|
errorThrow("Cutscene item (PARTY_ADD_MEMBER): no member with key '%s'", key);
|
||||||
|
}
|
||||||
|
item->partyAddMember.memberIndex = memberIndex;
|
||||||
|
|
||||||
errorOk();
|
errorOk();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,8 @@
|
|||||||
#include "rpg/cutscene/item/cutsceneitembase.h"
|
#include "rpg/cutscene/item/cutsceneitembase.h"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
// Resolved from the JSON 'key' field at load time (see
|
||||||
|
// partyGetMemberIndexByKey) - not a raw JSON field itself.
|
||||||
uint8_t memberIndex;
|
uint8_t memberIndex;
|
||||||
} cutscenepartyaddmember_t;
|
} cutscenepartyaddmember_t;
|
||||||
|
|
||||||
@@ -39,7 +41,8 @@ bool_t cutscenePartyAddMemberUpdate(
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses a PARTY_ADD_MEMBER cutscene item's JSON fields into item:
|
* Parses a PARTY_ADD_MEMBER cutscene item's JSON fields into item:
|
||||||
* 'memberIndex', a required integer roster index.
|
* 'key', a required string matching a party.jsonc member key, resolved to
|
||||||
|
* its roster index via partyGetMemberIndexByKey.
|
||||||
*
|
*
|
||||||
* @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.
|
||||||
|
|||||||
@@ -27,13 +27,16 @@ errorret_t cutscenePartyHealMemberLoad(
|
|||||||
yyjson_val *itemObj,
|
yyjson_val *itemObj,
|
||||||
cutsceneitem_t *item
|
cutsceneitem_t *item
|
||||||
) {
|
) {
|
||||||
const int32_t memberIndex = cutsceneJsonGetInt(itemObj, "memberIndex", -1);
|
char_t key[PARTY_KEY_LENGTH_MAX];
|
||||||
if(memberIndex < 0 || memberIndex >= PARTY_MEMBER_COUNT_MAX) {
|
if(!cutsceneJsonCopyString(itemObj, "key", NULL, key, PARTY_KEY_LENGTH_MAX)) {
|
||||||
errorThrow(
|
errorThrow("Cutscene item (PARTY_HEAL_MEMBER): missing/invalid 'key'");
|
||||||
"Cutscene item (PARTY_HEAL_MEMBER): invalid/missing 'memberIndex'"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
item->partyHealMember.memberIndex = (uint8_t)memberIndex;
|
|
||||||
|
const uint8_t memberIndex = partyGetMemberIndexByKey(key);
|
||||||
|
if(memberIndex == PARTY_MEMBER_NOT_FOUND) {
|
||||||
|
errorThrow("Cutscene item (PARTY_HEAL_MEMBER): no member with key '%s'", key);
|
||||||
|
}
|
||||||
|
item->partyHealMember.memberIndex = memberIndex;
|
||||||
|
|
||||||
errorOk();
|
errorOk();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,8 @@
|
|||||||
#include "rpg/cutscene/item/cutsceneitembase.h"
|
#include "rpg/cutscene/item/cutsceneitembase.h"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
// Resolved from the JSON 'key' field at load time (see
|
||||||
|
// partyGetMemberIndexByKey) - not a raw JSON field itself.
|
||||||
uint8_t memberIndex;
|
uint8_t memberIndex;
|
||||||
} cutscenepartyhealmember_t;
|
} cutscenepartyhealmember_t;
|
||||||
|
|
||||||
@@ -38,7 +40,8 @@ bool_t cutscenePartyHealMemberUpdate(
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses a PARTY_HEAL_MEMBER cutscene item's JSON fields into item:
|
* Parses a PARTY_HEAL_MEMBER cutscene item's JSON fields into item:
|
||||||
* 'memberIndex', a required integer roster index.
|
* 'key', a required string matching a party.jsonc member key, resolved to
|
||||||
|
* its roster index via partyGetMemberIndexByKey.
|
||||||
*
|
*
|
||||||
* @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.
|
||||||
|
|||||||
@@ -27,13 +27,18 @@ errorret_t cutscenePartyRemoveMemberLoad(
|
|||||||
yyjson_val *itemObj,
|
yyjson_val *itemObj,
|
||||||
cutsceneitem_t *item
|
cutsceneitem_t *item
|
||||||
) {
|
) {
|
||||||
const int32_t memberIndex = cutsceneJsonGetInt(itemObj, "memberIndex", -1);
|
char_t key[PARTY_KEY_LENGTH_MAX];
|
||||||
if(memberIndex < 0 || memberIndex >= PARTY_MEMBER_COUNT_MAX) {
|
if(!cutsceneJsonCopyString(itemObj, "key", NULL, key, PARTY_KEY_LENGTH_MAX)) {
|
||||||
|
errorThrow("Cutscene item (PARTY_REMOVE_MEMBER): missing/invalid 'key'");
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint8_t memberIndex = partyGetMemberIndexByKey(key);
|
||||||
|
if(memberIndex == PARTY_MEMBER_NOT_FOUND) {
|
||||||
errorThrow(
|
errorThrow(
|
||||||
"Cutscene item (PARTY_REMOVE_MEMBER): invalid/missing 'memberIndex'"
|
"Cutscene item (PARTY_REMOVE_MEMBER): no member with key '%s'", key
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
item->partyRemoveMember.memberIndex = (uint8_t)memberIndex;
|
item->partyRemoveMember.memberIndex = memberIndex;
|
||||||
|
|
||||||
errorOk();
|
errorOk();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,8 @@
|
|||||||
#include "rpg/cutscene/item/cutsceneitembase.h"
|
#include "rpg/cutscene/item/cutsceneitembase.h"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
// Resolved from the JSON 'key' field at load time (see
|
||||||
|
// partyGetMemberIndexByKey) - not a raw JSON field itself.
|
||||||
uint8_t memberIndex;
|
uint8_t memberIndex;
|
||||||
} cutscenepartyremovemember_t;
|
} cutscenepartyremovemember_t;
|
||||||
|
|
||||||
@@ -39,7 +41,8 @@ bool_t cutscenePartyRemoveMemberUpdate(
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses a PARTY_REMOVE_MEMBER cutscene item's JSON fields into item:
|
* Parses a PARTY_REMOVE_MEMBER cutscene item's JSON fields into item:
|
||||||
* 'memberIndex', a required integer roster index.
|
* 'key', a required string matching a party.jsonc member key, resolved to
|
||||||
|
* its roster index via partyGetMemberIndexByKey.
|
||||||
*
|
*
|
||||||
* @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.
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
#include "uibattlehud.h"
|
#include "uibattlehud.h"
|
||||||
#include "rpg/battle/battle.h"
|
#include "rpg/battle/battle.h"
|
||||||
|
#include "rpg/battle/party.h"
|
||||||
#include "scene/battle/scenebattle.h"
|
#include "scene/battle/scenebattle.h"
|
||||||
#include "scene/scene.h"
|
#include "scene/scene.h"
|
||||||
#include "display/text/text.h"
|
#include "display/text/text.h"
|
||||||
@@ -58,22 +59,28 @@ errorret_t uiBattleHudDraw(void) {
|
|||||||
vec2 screenPos;
|
vec2 screenPos;
|
||||||
sceneBattleWorldToScreen(battle, position, screenPos);
|
sceneBattleWorldToScreen(battle, position, screenPos);
|
||||||
|
|
||||||
|
float_t lineY = screenPos[1];
|
||||||
|
if(fighter->team == BATTLE_FIGHTER_TEAM_ALLY) {
|
||||||
|
errorChain(textDraw(
|
||||||
|
screenPos[0], lineY, partyGetMemberKey(fighter->id), COLOR_WHITE, NULL
|
||||||
|
));
|
||||||
|
lineY += UI_BATTLE_HUD_LINE_HEIGHT;
|
||||||
|
}
|
||||||
|
|
||||||
char_t hpText[UI_BATTLE_HUD_TEXT_MAX];
|
char_t hpText[UI_BATTLE_HUD_TEXT_MAX];
|
||||||
stringFormat(
|
stringFormat(
|
||||||
hpText, UI_BATTLE_HUD_TEXT_MAX - 1, UI_BATTLE_HUD.hpFormat,
|
hpText, UI_BATTLE_HUD_TEXT_MAX - 1, UI_BATTLE_HUD.hpFormat,
|
||||||
fighter->stats.health, fighter->stats.healthMax
|
fighter->stats.health, fighter->stats.healthMax
|
||||||
);
|
);
|
||||||
errorChain(textDraw(screenPos[0], screenPos[1], hpText, COLOR_WHITE, NULL));
|
errorChain(textDraw(screenPos[0], lineY, hpText, COLOR_WHITE, NULL));
|
||||||
|
lineY += UI_BATTLE_HUD_LINE_HEIGHT;
|
||||||
|
|
||||||
char_t mpText[UI_BATTLE_HUD_TEXT_MAX];
|
char_t mpText[UI_BATTLE_HUD_TEXT_MAX];
|
||||||
stringFormat(
|
stringFormat(
|
||||||
mpText, UI_BATTLE_HUD_TEXT_MAX - 1, UI_BATTLE_HUD.mpFormat,
|
mpText, UI_BATTLE_HUD_TEXT_MAX - 1, UI_BATTLE_HUD.mpFormat,
|
||||||
fighter->stats.mp, fighter->stats.mpMax
|
fighter->stats.mp, fighter->stats.mpMax
|
||||||
);
|
);
|
||||||
errorChain(textDraw(
|
errorChain(textDraw(screenPos[0], lineY, mpText, COLOR_CYAN, NULL));
|
||||||
screenPos[0], screenPos[1] + UI_BATTLE_HUD_LINE_HEIGHT,
|
|
||||||
mpText, COLOR_CYAN, NULL
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
errorChain(spriteBatchFlush());
|
errorChain(spriteBatchFlush());
|
||||||
|
|||||||
@@ -12,8 +12,11 @@
|
|||||||
#include "util/string.h"
|
#include "util/string.h"
|
||||||
#include "display/spritebatch/spritebatch.h"
|
#include "display/spritebatch/spritebatch.h"
|
||||||
#include "display/screen/screen.h"
|
#include "display/screen/screen.h"
|
||||||
|
#include "display/text/text.h"
|
||||||
|
#include "display/color.h"
|
||||||
#include "locale/localemanager.h"
|
#include "locale/localemanager.h"
|
||||||
#include "asset/loader/locale/assetlocaleloader.h"
|
#include "asset/loader/locale/assetlocaleloader.h"
|
||||||
|
#include "rpg/battle/party.h"
|
||||||
|
|
||||||
uibattlemenu_t UI_BATTLE_MENU;
|
uibattlemenu_t UI_BATTLE_MENU;
|
||||||
|
|
||||||
@@ -141,6 +144,14 @@ errorret_t uiBattleMenuDraw(void) {
|
|||||||
const float_t x = (float_t)(SCREEN.scanX + SCREEN.scanWidth) - width;
|
const float_t x = (float_t)(SCREEN.scanX + SCREEN.scanWidth) - width;
|
||||||
const float_t y = (float_t)(SCREEN.scanY + SCREEN.scanHeight) - height;
|
const float_t y = (float_t)(SCREEN.scanY + SCREEN.scanHeight) - height;
|
||||||
|
|
||||||
|
battlefighter_t *current = battleStateSelectionGetCurrentFighter();
|
||||||
|
if(current != NULL) {
|
||||||
|
errorChain(textDraw(
|
||||||
|
x, y - UI_BATTLE_MENU_NAME_LINE_HEIGHT,
|
||||||
|
partyGetMemberKey(current->id), COLOR_WHITE, NULL
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
errorChain(uiFrameDraw(x, y, width, height));
|
errorChain(uiFrameDraw(x, y, width, height));
|
||||||
errorChain(uiMenuDraw(
|
errorChain(uiMenuDraw(
|
||||||
&UI_BATTLE_MENU.actionMenu,
|
&UI_BATTLE_MENU.actionMenu,
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
|
|
||||||
#define UI_BATTLE_MENU_WIDTH 160.0f
|
#define UI_BATTLE_MENU_WIDTH 160.0f
|
||||||
#define UI_BATTLE_MENU_HEIGHT 96.0f
|
#define UI_BATTLE_MENU_HEIGHT 96.0f
|
||||||
|
#define UI_BATTLE_MENU_NAME_LINE_HEIGHT 12.0f
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uimenu_t actionMenu;
|
uimenu_t actionMenu;
|
||||||
|
|||||||
@@ -26,10 +26,10 @@ static char_t SAVE_TEST_FIXTURE_REAL_HOME[PATH_MAX];
|
|||||||
static bool_t SAVE_TEST_FIXTURE_HAD_REAL_HOME;
|
static bool_t SAVE_TEST_FIXTURE_HAD_REAL_HOME;
|
||||||
|
|
||||||
static const char_t *SAVE_TEST_FIXTURE_PARTY_JSON =
|
static const char_t *SAVE_TEST_FIXTURE_PARTY_JSON =
|
||||||
"{\"members\":[{"
|
"{\"members\":{\"hero\":{"
|
||||||
"\"attack\":10,\"defense\":5,\"magic\":0,\"speed\":10,\"luck\":0,"
|
"\"attack\":10,\"defense\":5,\"magic\":0,\"speed\":10,\"luck\":0,"
|
||||||
"\"healthMax\":30,\"mpMax\":10"
|
"\"healthMax\":30,\"mpMax\":10"
|
||||||
"}]}";
|
"}}}";
|
||||||
|
|
||||||
static yyjson_doc *SAVE_TEST_FIXTURE_PARTY_DOC = NULL;
|
static yyjson_doc *SAVE_TEST_FIXTURE_PARTY_DOC = NULL;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user