diff --git a/src/window_base.cpp b/src/window_base.cpp index 5c0c436821..59104e4f79 100644 --- a/src/window_base.cpp +++ b/src/window_base.cpp @@ -302,38 +302,6 @@ void Window_Base::DrawCurrencyValue(int money, int cx, int cy) const { contents->TextDraw(cx - gold_text_size.width, cy, Font::ColorDefault, gold.str(), Text::AlignRight); } -void Window_Base::DrawGauge(const Game_Battler& actor, int cx, int cy, int alpha) const { - BitmapRef system2 = Cache::System2(); - if (!system2) { - return; - } - - bool full = actor.IsAtbGaugeFull(); - - // Which gauge (0 - 2) - int gauge_y = 32 + 2 * 16; - - // Three components of the gauge - Rect gauge_left(0, gauge_y, 16, 16); - Rect gauge_center(16, gauge_y, 16, 16); - Rect gauge_right(32, gauge_y, 16, 16); - - Rect dst_rect(cx + 16, cy, 25, 16); - - contents->Blit(cx + 0, cy, *system2, gauge_left, alpha); - contents->Blit(cx + 16 + 25, cy, *system2, gauge_right, alpha); - contents->StretchBlit(dst_rect, *system2, gauge_center, alpha); - - const auto atb = actor.GetAtbGauge(); - const auto gauge_w = 25 * atb / actor.GetMaxAtbGauge(); - if (gauge_w > 0) { - // Full or not full bar - Rect gauge_bar(full ? 64 : 48, gauge_y, 16, 16); - Rect bar_rect(cx + 16, cy, gauge_w, 16); - contents->StretchBlit(bar_rect, *system2, gauge_bar, alpha); - } -} - void Window_Base::DrawActorHpValue(const Game_Battler& actor, int cx, int cy) const { contents->TextDraw(cx, cy, GetValueFontColor(actor.GetHp(), actor.GetMaxHp(), true), std::to_string(actor.GetHp()), Text::AlignRight); } diff --git a/src/window_base.h b/src/window_base.h index 68afdd94bc..13542be639 100644 --- a/src/window_base.h +++ b/src/window_base.h @@ -67,7 +67,6 @@ class Window_Base : public Window { void DrawItemName(const lcf::rpg::Item& item, int cx, int cy, bool enabled = true) const; void DrawSkillName(const lcf::rpg::Skill& skill, int cx, int cy, bool enabled = true) const; void DrawCurrencyValue(int money, int cx, int cy) const; - void DrawGauge(const Game_Battler& actor, int cx, int cy, int alpha = 255) const; void DrawActorHpValue(const Game_Battler& actor, int cx, int cy) const; void DrawActorSpValue(const Game_Battler& actor, int cx, int cy) const; int GetValueFontColor(int have, int max, bool can_knockout) const; diff --git a/src/window_battlestatus.cpp b/src/window_battlestatus.cpp index f3be182ff7..d13033ccac 100644 --- a/src/window_battlestatus.cpp +++ b/src/window_battlestatus.cpp @@ -31,6 +31,7 @@ #include "window_battlestatus.h" #include "feature.h" + Window_BattleStatus::Window_BattleStatus(int ix, int iy, int iwidth, int iheight, bool enemy) : Window_Selectable(ix, iy, iwidth, iheight), mode(ChoiceMode_All), enemy(enemy) { @@ -57,13 +58,21 @@ Window_BattleStatus::Window_BattleStatus(int ix, int iy, int iwidth, int iheight SetContents(Bitmap::Create(width, height)); SetOpacity(0); } - + isEmpty = true; Refresh(); } void Window_BattleStatus::Refresh() { - contents->Clear(); - + // If the battle system uses gauges, wait for system2 to load. + if (!Feature::HasRpg2kBattleSystem() && !Cache::System2() ) { + return; + } + // This avoids an issue where smaller face graphics (found in the game Ara Fell, as mentioned below in RefreshGauge) + // will be stretched to fill the full face area, before the window is visible. I am not sure why that happens. + if (!IsVisible()) { + return; + } + if (enemy) { item_max = Main_Data::game_enemyparty->GetBattlerCount(); } @@ -73,122 +82,276 @@ void Window_BattleStatus::Refresh() { item_max = std::min(item_max, 4); + bool needs_redraw = false; + // Check if any actor IDs have changed, and if so, redraw the whole window. for (int i = 0; i < item_max; i++) { - // The party only contains valid battlers - const Game_Battler* actor; - if (enemy) { - actor = &(*Main_Data::game_enemyparty)[i]; + const Game_Battler* actor = GetActorForItem(i); + if (itemStates[i].actor_id != actor->GetId()) { + needs_redraw = true; + break; } - else { - actor = &(*Main_Data::game_party)[i]; + } + // Also redraw if we have any rows to remove + for (int i = item_max; i < 4; i++) { + if (itemStates[i].is_drawn) { + needs_redraw = true; + break; } - - if (!enemy && lcf::Data::battlecommands.battle_type == lcf::rpg::BattleCommands::BattleType_gauge) { - DrawActorFace(*static_cast(actor), 80 * i, actor_face_height); + } + if (needs_redraw) { + if (!isEmpty) { + contents->Clear(); + isEmpty = true; } - else { - int y = menu_item_height / 8 + i * menu_item_height; + for (int i = item_max; i < 4; i++) { + itemStates[i].reset(); + } + } - DrawActorName(*actor, 4, y); - if (Feature::HasRpg2kBattleSystem()) { + for (int i = 0; i < item_max; i++) { + // The party only contains valid battlers + const Game_Battler* actor = GetActorForItem(i); + itemStates[i].actor_id = actor->GetId(); + + bool hp_changed = itemStates[i].hp != actor->GetHp(); + bool hp_max_changed = itemStates[i].max_hp != actor->GetMaxHp(); + bool sp_changed = itemStates[i].sp != actor->GetSp(); + bool sp_max_changed = itemStates[i].max_sp != actor->GetMaxSp(); + + if (lcf::Data::battlecommands.battle_type != lcf::rpg::BattleCommands::BattleType_gauge || enemy) { + + + int y = menu_item_height / 8 + i * menu_item_height; + + const lcf::rpg::State* state = actor->GetSignificantState(); + bool state_changed = (state == NULL && itemStates[i].state_name.compare("") != 0 || itemStates[i].state_color != 0) + || (state != NULL && (itemStates[i].state_name.compare(ToString(state->name)) != 0 || itemStates[i].state_color != state->color)); + + + int state_x; + + if (Feature::HasRpg2kBattleSystem() && (hp_changed || hp_max_changed || sp_changed || sp_max_changed || state_changed)) { int hpdigits = (actor->MaxHpValue() >= 1000) ? 4 : 3; int spdigits = (actor->MaxSpValue() >= 1000) ? 4 : 3; - DrawActorState(*actor, (hpdigits < 4 && spdigits < 4) ? 86 : 80, y); + state_x = (hpdigits < 4 && spdigits < 4) ? 86 : 80; + int sp_x = 220 - spdigits * 6; + + // Just clear and redraw the whole Status/HP/MP area for now when something changes + if (!isEmpty) { contents->ClearRect(Rect(state_x, y, width - state_x, menu_item_height)); } + DrawActorState(*actor, state_x, y); DrawActorHp(*actor, 178 - hpdigits * 6 - spdigits * 6, y, hpdigits, true); - DrawActorSp(*actor, 220 - spdigits * 6, y, spdigits, false); - } else { + DrawActorSp(*actor, sp_x, y, spdigits, false); + + } else if (!Feature::HasRpg2kBattleSystem() && (hp_changed || hp_max_changed || state_changed)) { + // BattleType_traditional/Type A if (lcf::Data::battlecommands.battle_type == lcf::rpg::BattleCommands::BattleType_traditional) { - DrawActorState(*actor, 84, y); - DrawActorHpValue(*actor, 136 + 4 * 6, y); + state_x = 84; + int hp_x = 136 + 4 * 6; + // State is left aligned and HP is right aligned, so redraw both of them due to the variable amount of space between them. + if (!isEmpty) { contents->ClearRect(Rect(state_x, y, hp_x - state_x, menu_item_height)); } + DrawActorState(*actor, state_x, y); + DrawActorHpValue(*actor, hp_x, y); + // BattleType_alternative/Type B } else { - DrawActorState(*actor, 80, y); + state_x = 80; + if (state_changed) { + // Clear up to the gauge area + if (!isEmpty) { contents->ClearRect(Rect(state_x, y, 130 - state_x, menu_item_height)); } + DrawActorState(*actor, state_x, y); + } } } + + if (itemStates[i].actor_name.compare(actor->GetName())) { + if (!isEmpty) { contents->ClearRect(Rect(4, y, state_x - 4, menu_item_height)); } + DrawActorName(*actor, 4, y); + itemStates[i].actor_name = actor->GetName(); + } + itemStates[i].state_name = state ? ToString(state->name) : ""; + itemStates[i].state_color = state ? state->color : 0; } + + RefreshGauge(actor, i, hp_changed, hp_max_changed, sp_changed, sp_max_changed); + + itemStates[i].hp = actor->GetHp(); + itemStates[i].max_hp = actor->GetMaxHp(); + itemStates[i].sp = actor->GetSp(); + itemStates[i].max_sp = actor->GetMaxSp(); + + itemStates[i].is_drawn = true; } + isEmpty = false; +} - RefreshGauge(); +const Game_Battler* Window_BattleStatus::GetActorForItem(int i_actor) { + if (enemy) { + return &(*Main_Data::game_enemyparty)[i_actor]; + } + else { + return &(*Main_Data::game_party)[i_actor]; + } } -void Window_BattleStatus::RefreshGauge() { - if (Feature::HasRpg2k3BattleSystem()) { - if (lcf::Data::battlecommands.battle_type == lcf::rpg::BattleCommands::BattleType_alternative) { - if (lcf::Data::battlecommands.window_size == lcf::rpg::BattleCommands::WindowSize_small) { - contents->ClearRect(Rect(192, 0, 45, 58)); - } else { - contents->ClearRect(Rect(192, 0, 45, 64)); - } - } +void Window_BattleStatus::RefreshGauge(const Game_Battler* actor, int i_item, bool hp_changed, bool hp_max_changed, bool sp_changed, bool sp_max_changed) { - for (int i = 0; i < item_max; ++i) { - // The party always contains valid battlers - Game_Battler* actor; - if (enemy) { - actor = &(*Main_Data::game_enemyparty)[i]; + if (!Feature::HasRpg2k3BattleSystem()) { + return; + } + + bool atb_bar_full = actor->IsAtbGaugeFull(); + int atb_bar_w; + + // There are multiple gauges to draw for BattleType_gauge/Type C + if (!enemy && lcf::Data::battlecommands.battle_type == lcf::rpg::BattleCommands::BattleType_gauge) { + BitmapRef system2 = Cache::System2(); + assert(system2); + + atb_bar_w = GaugeWidthSystem2(actor->GetAtbGauge(), actor->GetMaxAtbGauge()); + const int x_start = 32 + i_item * 80; + const int fill_x = x_start + 16; + int y = actor_face_height; + + const Game_Actor* game_actor = static_cast(actor); + bool face_changed = game_actor->GetFaceName().compare(itemStates[i_item].face_name) != 0 || game_actor->GetFaceIndex() != itemStates[i_item].face_index; + // If the HP or SP have changed, 4-digit numbers can overlap the face graphic. The face graphic + // is also overlapped by the gauge graphics, so just redraw everything. (also do this if the ATB gauge resets.) + // Could be fine-tuned, but performance seems ok for now. + if (hp_changed || hp_max_changed || sp_changed || sp_max_changed || face_changed || atb_bar_w < itemStates[i_item].atb_bar_width) { + + if (!isEmpty && face_changed) { + // If the face graphic changed, clear the entire available area for this actor item. + contents->ClearRect(Rect(80 * i_item, 0, 80, height)); } - else { - actor = &(*Main_Data::game_party)[i]; + else if (!isEmpty) { + // Otherwise, just clear the part of the face that could be overlapped by the numbers. + // Note that both clear and redraw are needed because some games don't have + // face graphics that are huge enough to clear the left side of the number area (e.g. Ara Fell) + contents->ClearRect(Rect(40 + 80 * i_item, actor_face_height, 8 * 4, 48)); } + + DrawActorFace(*static_cast(actor), 80 * i_item, actor_face_height); + + int x = x_start; + + // Left Gauge Segments + contents->Blit(x, y, *system2, Rect(0, 32, 16, 48), Opacity::Opaque()); + x += 16; + + // Center + contents->StretchBlit(Rect(x, y, 25, 48), *system2, Rect(16, 32, 16, 48), Opacity::Opaque()); + x += 25; + + // Right + contents->Blit(x, y, *system2, Rect(32, 32, 16, 48), Opacity::Opaque()); + + // HP + DrawGaugeSystem2(fill_x, y, actor->GetHp(), actor->GetMaxHp(), 0); + // SP + DrawGaugeSystem2(fill_x, y + 16, actor->GetSp(), actor->GetMaxSp(), 1); + // ATB + DrawGaugeSystem2(fill_x, y + 16 * 2, actor->GetAtbGauge(), actor->GetMaxAtbGauge(), 2); + + // Numbers + x = 40 + 80 * i_item; + DrawNumberSystem2(x, y, actor->GetHp()); + DrawNumberSystem2(x, y + 12 + 4, actor->GetSp()); + + itemStates[i_item].face_name = game_actor->GetFaceName(); + itemStates[i_item].face_index = game_actor->GetFaceIndex(); + } + // If only the ATB gauge has only updated (common), we can get away with only drawing the gauge bar + else if (atb_bar_w > itemStates[i_item].atb_bar_width || atb_bar_full != itemStates[i_item].atb_bar_full) { + DrawGaugeSystem2(fill_x, y + 16 * 2, actor->GetAtbGauge(), actor->GetMaxAtbGauge(), 2); + } + itemStates[i_item].atb_bar_width = atb_bar_w; + itemStates[i_item].atb_bar_full = atb_bar_full; + } + else { + int y = menu_item_height / 8 + i_item * menu_item_height; + atb_bar_w = GaugeWidth(actor->GetAtbGauge(), actor->GetMaxAtbGauge()); - if (!enemy && lcf::Data::battlecommands.battle_type == lcf::rpg::BattleCommands::BattleType_gauge) { - BitmapRef system2 = Cache::System2(); - if (system2) { - // Clear number and gauge drawing area - contents->ClearRect(Rect(40 + 80 * i, actor_face_height, 8 * 4, 48)); - - // Number clearing removed part of the face, but both, clear and redraw - // are needed because some games don't have face graphics that are huge enough - // to clear the number area (e.g. Ara Fell) - DrawActorFace(*static_cast(actor), 80 * i, actor_face_height); - - int x = 32 + i * 80; - int y = actor_face_height; - - // Left Gauge - contents->Blit(x, y, *system2, Rect(0, 32, 16, 48), Opacity::Opaque()); - x += 16; - - // Center - const auto fill_x = x; - contents->StretchBlit(Rect(x, y, 25, 48), *system2, Rect(16, 32, 16, 48), Opacity::Opaque()); - x += 25; - - // Right - contents->Blit(x, y, *system2, Rect(32, 32, 16, 48), Opacity::Opaque()); - - // HP - DrawGaugeSystem2(fill_x, y, actor->GetHp(), actor->GetMaxHp(), 0); - // SP - DrawGaugeSystem2(fill_x, y + 16, actor->GetSp(), actor->GetMaxSp(), 1); - // Gauge - DrawGaugeSystem2(fill_x, y + 16 * 2, actor->GetAtbGauge(), actor->GetMaxAtbGauge(), 2); - - // Numbers - x = 40 + 80 * i; - DrawNumberSystem2(x, y, actor->GetHp()); - DrawNumberSystem2(x, y + 12 + 4, actor->GetSp()); + // BattleType_alternative/Type B has a lot of overlapping content, and is the trickiest one to optimize. + if (lcf::Data::battlecommands.battle_type == lcf::rpg::BattleCommands::BattleType_alternative) { + int spdigits = (actor->MaxSpValue() >= 1000) ? 4 : 3; + bool has_opaque_gauge = lcf::Data::battlecommands.transparency == lcf::rpg::BattleCommands::Transparency_opaque || (menu_item_height / 8 + index * menu_item_height != y); + bool didUpdate = false; + // If any of these have changed, then full clear and redraw since there's so much overlap. + if (hp_changed || hp_max_changed || sp_changed || sp_max_changed || atb_bar_w < itemStates[i_item].atb_bar_width || has_opaque_gauge != itemStates[i_item].has_opaque_gauge) { + if (!isEmpty) { + contents->ClearRect(Rect(130, y, width - 130, menu_item_height)); + } + // RPG_RT Bug (?): Gauge hidden when selected due to transparency (wrong color when rendering) + if (has_opaque_gauge) { + DrawGauge(202 - 10, y - 2, actor->GetAtbGauge(), actor->GetMaxAtbGauge(), actor->IsAtbGaugeFull(), true, + lcf::Data::battlecommands.transparency == lcf::rpg::BattleCommands::Transparency_opaque ? 96 : 255); } + int hpdigits = (actor->MaxHpValue() >= 1000) ? 4 : 3; + DrawActorHp(*actor, 178 - hpdigits * 6 - spdigits * 6, y, hpdigits, true); + didUpdate = true; } - else { - int y = menu_item_height / 8 + i * menu_item_height; - - if (lcf::Data::battlecommands.battle_type == lcf::rpg::BattleCommands::BattleType_alternative) { - // RPG_RT Bug (?): Gauge hidden when selected due to transparency (wrong color when rendering) - if (lcf::Data::battlecommands.transparency == lcf::rpg::BattleCommands::Transparency_opaque || (menu_item_height / 8 + index * menu_item_height != y)) { - DrawGauge(*actor, 202 - 10, y - 2, lcf::Data::battlecommands.transparency == lcf::rpg::BattleCommands::Transparency_opaque ? 96 : 255); - } - int hpdigits = (actor->MaxHpValue() >= 1000) ? 4 : 3; - int spdigits = (actor->MaxSpValue() >= 1000) ? 4 : 3; - DrawActorHp(*actor, 178 - hpdigits * 6 - spdigits * 6, y, hpdigits, true); - DrawActorSp(*actor, 220 - spdigits * 6, y, spdigits, false); - } else { - DrawGauge(*actor, 156, y - 2); + // Only the ATB gauge has increased + else if (atb_bar_w > itemStates[i_item].atb_bar_width || atb_bar_full != itemStates[i_item].atb_bar_full) { + if (has_opaque_gauge) { + DrawGauge(202 - 10, y - 2, actor->GetAtbGauge(), actor->GetMaxAtbGauge(), actor->IsAtbGaugeFull(), false, + lcf::Data::battlecommands.transparency == lcf::rpg::BattleCommands::Transparency_opaque ? 96 : 255); } + didUpdate = true; + } + // The SP number overlaps the gauge bar, so it needs to be redrawn if any drawing was done above. + if (didUpdate) { + DrawActorSp(*actor, 220 - spdigits * 6, y, spdigits, false); + itemStates[i_item].atb_bar_width = atb_bar_w; + itemStates[i_item].atb_bar_full = atb_bar_full; + } + itemStates[i_item].has_opaque_gauge = has_opaque_gauge; + } else { + // BattleType_traditional/Type A + if (atb_bar_w != itemStates[i_item].atb_bar_width || atb_bar_full != itemStates[i_item].atb_bar_full) { + bool shouldDrawGraphic = atb_bar_w < itemStates[i_item].atb_bar_width; + DrawGauge(156, y - 2, actor->GetAtbGauge(), actor->GetMaxAtbGauge(), actor->IsAtbGaugeFull(), shouldDrawGraphic); } + itemStates[i_item].atb_bar_width = atb_bar_w; + itemStates[i_item].atb_bar_full = atb_bar_full; } + } } +// This draws the ATB gauge for BattleType_Traditional (Type A) and BattleType_alternative (Type B) +void Window_BattleStatus::DrawGauge(int cx, int cy, int cur_value, int max_value, bool is_full, bool draw_graphic, int alpha) { + BitmapRef system2 = Cache::System2(); + assert(system2); + int gauge_w = GaugeWidth(cur_value, max_value); + + // Use the Y position for the gauge at index 2 + int gauge_y = 32 + 2 * 16; + + if (draw_graphic) { + // Three components of the gauge + Rect gauge_left(0, gauge_y, 16, 16); + Rect gauge_center(16, gauge_y, 16, 16); + Rect gauge_right(32, gauge_y, 16, 16); + + Rect dst_rect(cx + 16, cy, 25, 16); + + contents->Blit(cx + 0, cy, *system2, gauge_left, alpha); + contents->Blit(cx + 16 + 25, cy, *system2, gauge_right, alpha); + contents->StretchBlit(dst_rect, *system2, gauge_center, alpha); + } + + // Draw the bar + if (gauge_w > 0) { + // Full or not full bar + Rect gauge_bar(is_full ? 64 : 48, gauge_y, 16, 16); + Rect bar_rect(cx + 16, cy, gauge_w, 16); + contents->StretchBlit(bar_rect, *system2, gauge_bar, alpha); + } +} + +int Window_BattleStatus::GaugeWidth(int cur_value, int max_value) { + return 25 * cur_value / max_value; +} + void Window_BattleStatus::DrawGaugeSystem2(int x, int y, int cur_value, int max_value, int which) { BitmapRef system2 = Cache::System2(); assert(system2); @@ -205,13 +368,16 @@ void Window_BattleStatus::DrawGaugeSystem2(int x, int y, int cur_value, int max_ gauge_x = 0; } - int gauge_width = 25; + int gauge_width = GaugeWidthSystem2(cur_value, max_value); + + contents->StretchBlit(Rect(x, y, gauge_width, 16), *system2, Rect(48 + gauge_x, 32 + 16 * which, 16, 16), Opacity::Opaque()); +} +int Window_BattleStatus::GaugeWidthSystem2(int cur_value, int max_value) { if (max_value > 0) { - gauge_width = 25 * cur_value / max_value; + return 25 * cur_value / max_value; } - - contents->StretchBlit(Rect(x, y, gauge_width, 16), *system2, Rect(48 + gauge_x, 32 + 16 * which, 16, 16), Opacity::Opaque()); + return 25; } void Window_BattleStatus::DrawNumberSystem2(int x, int y, int value) { @@ -276,10 +442,8 @@ void Window_BattleStatus::Update() { item_max = Main_Data::game_party->GetBattlerCount(); } - if (item_max != old_item_max) { + if (item_max != old_item_max || Feature::HasRpg2k3BattleSystem()) { Refresh(); - } else if (Feature::HasRpg2k3BattleSystem()) { - RefreshGauge(); } if (active && index >= 0) { diff --git a/src/window_battlestatus.h b/src/window_battlestatus.h index 046beacdf6..6602c69505 100644 --- a/src/window_battlestatus.h +++ b/src/window_battlestatus.h @@ -47,7 +47,8 @@ class Window_BattleStatus : public Window_Selectable { Window_BattleStatus(int ix, int iy, int iwidth, int iheight, bool enemy = false); /** - * Renders the current status on the window. + * Renders the current status on the window. Updates incrementally, based on current party state when called. + * This allows Refresh() to be called every frame without significant CPU load. */ void Refresh(); @@ -77,11 +78,40 @@ class Window_BattleStatus : public Window_Selectable { void UpdateCursorRect() override; /** - * Redraws the characters time gauge. + * Get the appropriate actor for the index from the player or enemy party. + */ + const Game_Battler* GetActorForItem(int i_actor); + + /** + * Redraws the characters time gauge, as well as HP and SP if applicable. + */ + void RefreshGauge(const Game_Battler* actor, int i_item, bool hp_changed, bool hp_max_changed, bool sp_changed, bool sp_max_changed); + + /** + * Draw the time gauge for BattleType_traditional (A) and BattleType_alternative (B). + */ + void DrawGauge(int cx, int cy, int cur_value, int max_value, bool is_full, bool draw_graphic, int alpha = 255); + + /** + * Used to determine if the ATB gauge needs redrawing. + * + * @return the pixel width of the ATB gauge + */ + int GaugeWidth(int cur_value, int max_value); + + /** + * Draw the gauge bars for Battletype_gauge (C) */ - void RefreshGauge(); - void DrawGaugeSystem2(int x, int y, int cur_value, int max_value, int which); + /** + * Used to determine if the a gauge needs redrawing. + * + * @return the pixel width of the HP, SP, or ATB gauge + */ + int GaugeWidthSystem2(int cur_value, int max_value); + /** + * Draw the time gauge for Battletype_gauge (C) + */ void DrawNumberSystem2(int x, int y, int value); /** @@ -93,12 +123,58 @@ class Window_BattleStatus : public Window_Selectable { ChoiceMode mode; + bool isEmpty = true; + // Debug helper bool enemy; FileRequestBinding request_id; int actor_face_height = 24; + struct BattleItemState { + int i_item = 0; + + bool is_drawn = false; + //bool has_drawn_face = false; + int actor_id = -1; // Full redraw if this changes + std::string actor_name = ""; + + int hp = -1; + int max_hp = -1; + int sp = -1; + int max_sp = -1; + std::string state_name = ""; + int32_t state_color; + + std::string face_name = ""; + int face_index = -1; + + int atb_bar_width = INT_MAX; + bool atb_bar_full = false; + bool has_opaque_gauge = true; + + void reset() { + is_drawn = false; + //has_drawn_face = false; + actor_id = -1; + actor_name = ""; + hp = -1; + max_hp = -1; + sp = -1; + max_sp = -1; + state_name = ""; + state_color = 0; + atb_bar_width = INT_MAX; + atb_bar_full = false; + has_opaque_gauge = true; + face_name = ""; + face_index = -1; + } + }; + + // Contains the current displayed data in this view. This is compared with + // new data, in order to make incremental updates to the UI. + BattleItemState itemStates[4]; }; #endif