diff --git a/src/audio_generic.cpp b/src/audio_generic.cpp index 8eba6bdc8d..2ae15af2c8 100644 --- a/src/audio_generic.cpp +++ b/src/audio_generic.cpp @@ -221,8 +221,9 @@ bool GenericAudio::PlayOnChannel(BgmChannel& chan, Filesystem_Stream::InputStrea chan.paused = true; // Pause channel so the audio thread doesn't work on it chan.stopped = false; // Unstop channel so the audio thread doesn't delete it + std::string_view name = filestream.GetName(); if (!filestream) { - Output::Warning("BGM file not readable: {}", filestream.GetName()); + Output::Warning("BGM file not readable: {}", name); return false; } @@ -272,7 +273,7 @@ bool GenericAudio::PlayOnChannel(BgmChannel& chan, Filesystem_Stream::InputStrea return true; } else { - Output::Warning("Couldn't play BGM {}. Format not supported", filestream.GetName()); + Output::Warning("Couldn't play BGM {}. Format not supported", name); } return false; diff --git a/src/game_character.cpp b/src/game_character.cpp index caf7ad8542..f6128442a9 100644 --- a/src/game_character.cpp +++ b/src/game_character.cpp @@ -1054,7 +1054,7 @@ bool Game_Character::CalculateMoveRoute(const CalculateMoveRouteArgs& args) { route.skippable = args.skip_when_failed; route.repeat = false; - for (SearchNode node2 : list_move) { + for (SearchNode const& node2 : list_move) { if (node2.direction >= 0) { lcf::rpg::MoveCommand cmd; cmd.command_id = node2.direction; diff --git a/src/plane.cpp b/src/plane.cpp index a779b059f4..d4c9806cd2 100644 --- a/src/plane.cpp +++ b/src/plane.cpp @@ -50,11 +50,13 @@ void Plane::Draw(Bitmap& dst) { int src_x = -ox - GetRenderOx(); int src_y = -oy - GetRenderOy(); + int offset_x = 0; + // Apply screen shaking const int shake_x = Main_Data::game_screen->GetShakeOffsetX(); const int shake_y = Main_Data::game_screen->GetShakeOffsetY(); if (Game_Map::LoopHorizontal()) { - src_x += shake_x; + offset_x = shake_x; } else { // The panorama occupies the same rectangle as the whole map. // Using coordinates where the top-left of the screen is the origin... @@ -82,11 +84,26 @@ void Plane::Draw(Bitmap& dst) { dst_rect.x = bg_x; dst_rect.width = bg_width; + if (Game_Map::GetDisplayX() / 16 + Player::screen_width > Game_Map::GetTilesX() * TILE_SIZE) { + // Do not draw out of bounds to the right + dst_rect.width -= (Game_Map::GetDisplayX() / 16 + Player::screen_width) - (Game_Map::GetTilesX() * TILE_SIZE); + } + // Correct the offset if the top-left corner moved. - src_x += shake_x + bg_x; + offset_x = shake_x + bg_x; } src_y += shake_y; - dst.TiledBlit(src_x, src_y, source->GetRect(), *source, dst_rect, 255); -} + dst.TiledBlit(src_x + offset_x, src_y, source->GetRect(), *source, dst_rect, 255); + if (!Game_Map::LoopHorizontal()) { + // Clear out of bounds map area visible during shake + if (offset_x < 0 && src_x + offset_x < 0) { + auto clear_rect = Rect(dst.GetRect().x, dst.GetRect().y, -offset_x, dst.GetRect().height); + dst.ClearRect(clear_rect); + } else if (dst_rect.width < Player::screen_width) { + auto clear_rect = Rect(dst_rect.width, dst.GetRect().y, Player::screen_width - dst_rect.width, dst.GetRect().height); + dst.ClearRect(clear_rect); + } + } +} diff --git a/src/sprite_timer.cpp b/src/sprite_timer.cpp index 79f926ba77..dc23bc52e3 100644 --- a/src/sprite_timer.cpp +++ b/src/sprite_timer.cpp @@ -23,6 +23,7 @@ #include "game_party.h" #include "game_system.h" #include "game_battle.h" +#include "window_message.h" #include Sprite_Timer::Sprite_Timer(int which) : @@ -90,7 +91,10 @@ void Sprite_Timer::Draw(Bitmap& dst) { if (Game_Battle::IsBattleRunning()) { SetY((Player::screen_height / 3 * 2) - 20); } - else if (Game_Message::IsMessageActive() && Game_Message::GetRealPosition() == 0) { + // RPG_RT doesn't check for the global setting for window positioning (Top/Middle/Bottom) + // here. It actually just checks for the Y position of the message window, regardless if + // it is active or visible. + else if (Game_Message::GetWindow()->GetY() < 20) { SetY(Player::screen_height - 20 - Player::menu_offset_y); } else { diff --git a/src/spriteset_battle.cpp b/src/spriteset_battle.cpp index c9dbcf632a..02fd57b3ed 100644 --- a/src/spriteset_battle.cpp +++ b/src/spriteset_battle.cpp @@ -31,7 +31,7 @@ #include "sprite_actor.h" #include "sprite_enemy.h" -Spriteset_Battle::Spriteset_Battle(const std::string bg_name, int terrain_id) +Spriteset_Battle::Spriteset_Battle(std::string bg_name, int terrain_id) { background_name = std::move(bg_name); diff --git a/src/window_item.cpp b/src/window_item.cpp index dedac43052..592452a2e7 100644 --- a/src/window_item.cpp +++ b/src/window_item.cpp @@ -108,26 +108,27 @@ void Window_Item::DrawItem(int index) { contents->ClearRect(rect); int item_id = data[index]; + if (item_id <= 0) + return; - if (item_id > 0) { - int number = Main_Data::game_party->GetItemCount(item_id); + int number = Main_Data::game_party->GetItemCount(item_id); - // Items are guaranteed to be valid - const lcf::rpg::Item* item = lcf::ReaderUtil::GetElement(lcf::Data::items, item_id); - if (actor) { - if (item->use_skill) { - number += actor->GetItemCount(item_id); - } + // Items are guaranteed to be valid + const lcf::rpg::Item* item = lcf::ReaderUtil::GetElement(lcf::Data::items, item_id); + if (actor) { + if (item->use_skill) { + number += actor->GetItemCount(item_id); } + } - bool enabled = CheckEnable(item_id); - DrawItemName(*item, rect.x, rect.y, enabled); + bool enabled = CheckEnable(item_id); + DrawItemName(*item, rect.x, rect.y, enabled); - Font::SystemColor color = enabled ? Font::ColorDefault : Font::ColorDisabled; - contents->TextDraw(rect.x + rect.width - 24, rect.y, color, fmt::format("{}{:3d}", lcf::rpg::Terms::TermOrDefault(lcf::Data::terms.easyrpg_item_number_separator, ":"), number)); - } + Font::SystemColor color = enabled ? Font::ColorDefault : Font::ColorDisabled; + contents->TextDraw(rect.x + rect.width - 24, rect.y, color, fmt::format("{}{:3d}", lcf::rpg::Terms::TermOrDefault(lcf::Data::terms.easyrpg_item_number_separator, ":"), number)); } + void Window_Item::UpdateHelp() { help_window->SetText(GetItem() == nullptr ? "" : ToString(GetItem()->description)); } diff --git a/src/window_message.cpp b/src/window_message.cpp index dbde321640..01da394396 100644 --- a/src/window_message.cpp +++ b/src/window_message.cpp @@ -189,11 +189,8 @@ void Window_Message::StartMessageProcessing(PendingMessage pm) { DebugLog("{}: MSG TEXT \n{}", text); - auto open_frames = (!IsVisible() && !Game_Battle::IsBattleRunning()) ? message_animation_frames : 0; - SetOpenAnimation(open_frames); - DebugLog("{}: MSG START OPEN {}", open_frames); - - InsertNewPage(); + disallow_next_message = true; + msg_was_pushed_this_frame = true; } void Window_Message::OnFinishPage() { @@ -399,7 +396,7 @@ void Window_Message::Update() { if (IsClosing()) { DebugLog("{}: MSG CLOSING"); } close_started_this_frame = false; - close_finished_this_frame = false; + disallow_next_message = false; const bool was_closing = IsClosing(); @@ -408,10 +405,22 @@ void Window_Message::Update() { gold_window->Update(); if (was_closing && !IsClosing()) { - close_finished_this_frame = true; + disallow_next_message = true; } if (!IsVisible()) { + if (msg_was_pushed_this_frame) { + msg_was_pushed_this_frame = false; + disallow_next_message = true; + return; + } + if (!text.empty() && text_index == text.data()) { + auto open_frames = (!IsVisible() && !Game_Battle::IsBattleRunning()) ? message_animation_frames : 0; + SetOpenAnimation(open_frames); + DebugLog("{}: MSG START OPEN {}", open_frames); + + InsertNewPage(); + } return; } diff --git a/src/window_message.h b/src/window_message.h index 8d90546968..4c5b10325d 100644 --- a/src/window_message.h +++ b/src/window_message.h @@ -165,8 +165,9 @@ class Window_Message: public Window_Selectable { // FIXME: This hacky flags exist because RPG_RT likely animates the message window // after the game loop finishes. Our code isn't structured that way, so we must hack // around it. + bool msg_was_pushed_this_frame = false; bool close_started_this_frame = false; - bool close_finished_this_frame = false; + bool disallow_next_message = false; /** Frames to wait when a message wait command was used */ int wait_count = 0; @@ -214,8 +215,8 @@ inline AsyncOp Window_Message::GetAsyncOp() const { } inline bool Window_Message::GetAllowNextMessage(bool foreground) const { - bool is_active = (IsVisible() || close_finished_this_frame); - return foreground ? !is_active || close_started_this_frame : !is_active; + bool is_active = (IsVisible() || disallow_next_message); + return foreground ? !is_active || (close_started_this_frame && !disallow_next_message): !is_active; } inline int Window_Message::GetMaxLinesPerPage() const { diff --git a/src/window_shopbuy.cpp b/src/window_shopbuy.cpp index 2b3ea45ae3..715a0bce83 100644 --- a/src/window_shopbuy.cpp +++ b/src/window_shopbuy.cpp @@ -57,27 +57,25 @@ void Window_ShopBuy::Refresh() { } void Window_ShopBuy::DrawItem(int index) { + Rect rect = GetItemRect(index); + contents->ClearRect(rect); + int item_id = data[index]; + if (item_id <= 0) + return; // (Shop) items are guaranteed to be valid const lcf::rpg::Item* item = lcf::ReaderUtil::GetElement(lcf::Data::items, item_id); - - int price = 0; - bool enabled = false; - if (!item) { Output::Warning("Window ShopBuy: Invalid item ID {}", item_id); - } else { - enabled = item->price <= Main_Data::game_party->GetGold() && Main_Data::game_party->GetItemCount(item_id) < Main_Data::game_party->GetMaxItemCount(item_id); - price = item->price; + return; } - Rect rect = GetItemRect(index); - contents->ClearRect(rect); + bool enabled = CheckEnable(item_id); DrawItemName(*item, rect.x, rect.y, enabled); - std::string str = std::to_string(price); - contents->TextDraw(rect.width, rect.y, enabled ? Font::ColorDefault : Font::ColorDisabled, str, Text::AlignRight); + Font::SystemColor color = enabled ? Font::ColorDefault : Font::ColorDisabled; + contents->TextDraw(rect.width, rect.y, color, std::to_string(item->price), Text::AlignRight); } void Window_ShopBuy::UpdateHelp() { diff --git a/src/window_skill.cpp b/src/window_skill.cpp index b237f9c7e0..91b2dc740b 100644 --- a/src/window_skill.cpp +++ b/src/window_skill.cpp @@ -76,18 +76,16 @@ void Window_Skill::DrawItem(int index) { contents->ClearRect(rect); int skill_id = data[index]; + if (skill_id <= 0) + return; - if (skill_id > 0) { - int costs = actor->CalculateSkillCost(skill_id); + bool enabled = CheckEnable(skill_id); + Font::SystemColor color = enabled ? Font::ColorDefault : Font::ColorDisabled; + int costs = actor->CalculateSkillCost(skill_id); + contents->TextDraw(rect.x + rect.width - 24, rect.y, color, fmt::format("{}{:3d}", lcf::rpg::Terms::TermOrDefault(lcf::Data::terms.easyrpg_skill_cost_separator, "-"), costs)); - bool enabled = CheckEnable(skill_id); - int color = !enabled ? Font::ColorDisabled : Font::ColorDefault; - - contents->TextDraw(rect.x + rect.width - 24, rect.y, color, fmt::format("{}{:3d}", lcf::rpg::Terms::TermOrDefault(lcf::Data::terms.easyrpg_skill_cost_separator, "-"), costs)); - - // Skills are guaranteed to be valid - DrawSkillName(*lcf::ReaderUtil::GetElement(lcf::Data::skills, skill_id), rect.x, rect.y, enabled); - } + // Skills are guaranteed to be valid + DrawSkillName(*lcf::ReaderUtil::GetElement(lcf::Data::skills, skill_id), rect.x, rect.y, enabled); } void Window_Skill::UpdateHelp() {