diff --git a/src/game_interpreter_control_variables.cpp b/src/game_interpreter_control_variables.cpp index aa241b3af3..e459695109 100644 --- a/src/game_interpreter_control_variables.cpp +++ b/src/game_interpreter_control_variables.cpp @@ -190,21 +190,11 @@ int ControlVariables::Event(int op, int event_id, const Game_BaseInterpreterCont break; case 4: { // Screen X - if (Player::game_config.fake_resolution.Get()) { - int pan_delta = (Game_Player::GetDefaultPanX() - lcf::rpg::SavePartyLocation::kPanXDefault) / TILE_SIZE; - return character->GetScreenX() - pan_delta; - } else { - return character->GetScreenX(); - } + return character->GetScreenX(); } case 5: { // Screen Y - if (Player::game_config.fake_resolution.Get()) { - int pan_delta = (Game_Player::GetDefaultPanY() - lcf::rpg::SavePartyLocation::kPanYDefault) / TILE_SIZE; - return character->GetScreenY() - pan_delta; - } else { - return character->GetScreenY(); - } + return character->GetScreenY(); } case 6: // Event ID diff --git a/src/game_map.cpp b/src/game_map.cpp index d6104f3a11..7f4d7168f2 100644 --- a/src/game_map.cpp +++ b/src/game_map.cpp @@ -1724,6 +1724,14 @@ void Game_Map::SetPositionX(int x, bool reset_panorama) { const int map_width = GetTilesX() * SCREEN_TILE_SIZE; if (LoopHorizontal()) { x = Utils::PositiveModulo(x, map_width); + + // If the map is too small to fit in the screen, add an offset corresponding to the black border's size + if (Player::game_config.fake_resolution.Get()) { + int map_width_in_pixels = Game_Map::GetTilesX() * TILE_SIZE; + if (map_width_in_pixels < Player::screen_width) { + x += ((Player::screen_width - map_width_in_pixels) / 2 / TILE_SIZE) * SCREEN_TILE_SIZE; + } + } } else { // Do not use std::clamp here. When the map is smaller than the screen the // upper bound is smaller than the lower bound making the function fail. @@ -1748,6 +1756,14 @@ void Game_Map::SetPositionY(int y, bool reset_panorama) { const int map_height = GetTilesY() * SCREEN_TILE_SIZE; if (LoopVertical()) { y = Utils::PositiveModulo(y, map_height); + + // If the map is too small to fit in the screen, add an offset corresponding to the black border's size + if (Player::game_config.fake_resolution.Get()) { + int map_height_in_pixels = Game_Map::GetTilesY() * TILE_SIZE; + if (map_height_in_pixels < Player::screen_height) { + y += ((Player::screen_height - map_height_in_pixels) / 2 / TILE_SIZE) * SCREEN_TILE_SIZE; + } + } } else { // Do not use std::clamp here. When the map is smaller than the screen the // upper bound is smaller than the lower bound making the function fail. @@ -2145,9 +2161,13 @@ void Game_Map::Parallax::ResetPositionX() { parallax_fake_x = false; if (!params.scroll_horz && !LoopHorizontal()) { + // What is the width of the panorama to display on screen? int pan_screen_width = Player::screen_width; - if (Player::game_config.fake_resolution.Get()) { - pan_screen_width = SCREEN_TARGET_WIDTH; + if (Player::game_config.fake_resolution.Get()) { + int map_width = Game_Map::GetTilesX() * TILE_SIZE; + if (map_width < pan_screen_width) { + pan_screen_width = map_width; + } } int tiles_per_screen = pan_screen_width / TILE_SIZE; @@ -2183,9 +2203,13 @@ void Game_Map::Parallax::ResetPositionY() { parallax_fake_y = false; if (!params.scroll_vert && !Game_Map::LoopVertical()) { + // What is the height of the panorama to display on screen? int pan_screen_height = Player::screen_height; if (Player::game_config.fake_resolution.Get()) { - pan_screen_height = SCREEN_TARGET_HEIGHT; + int map_height = Game_Map::GetTilesY() * TILE_SIZE; + if (map_height < pan_screen_height) { + pan_screen_height = map_height; + } } int tiles_per_screen = pan_screen_height / TILE_SIZE; diff --git a/src/game_player.cpp b/src/game_player.cpp index 6ffa40082c..ce34065a00 100644 --- a/src/game_player.cpp +++ b/src/game_player.cpp @@ -191,15 +191,33 @@ void Game_Player::UpdateScroll(int amount, bool was_jumping) { return; } - auto dx = (GetX() * SCREEN_TILE_SIZE) - Game_Map::GetPositionX() - GetPanX(); - auto dy = (GetY() * SCREEN_TILE_SIZE) - Game_Map::GetPositionY() - GetPanY(); + const auto map_width = Game_Map::GetTilesX() * SCREEN_TILE_SIZE; + const auto map_height = Game_Map::GetTilesY() * SCREEN_TILE_SIZE; + + // When using FakeResolution mode, if the map is too small to fit the screen + // we need to calculate the black border offset, in case of a looping map for example + int screen_offset_x = 0; + if (Player::game_config.fake_resolution.Get()) { + int map_width_in_pixels = Game_Map::GetTilesX() * TILE_SIZE; + if (map_width_in_pixels < Player::screen_width) { + screen_offset_x = ((Player::screen_width - map_width_in_pixels) / 2 / TILE_SIZE) * SCREEN_TILE_SIZE; + } + } + int screen_offset_y = 0; + if (Player::game_config.fake_resolution.Get()) { + int map_height_in_pixels = Game_Map::GetTilesY() * TILE_SIZE; + if (map_height_in_pixels < Player::screen_height) { + screen_offset_y = ((Player::screen_height - map_height_in_pixels) / 2 / TILE_SIZE) * SCREEN_TILE_SIZE; + } + } - const auto w = Game_Map::GetTilesX() * SCREEN_TILE_SIZE; - const auto h = Game_Map::GetTilesY() * SCREEN_TILE_SIZE; + auto dx = (GetX() * SCREEN_TILE_SIZE) - Game_Map::GetPositionX() - GetPanX() + screen_offset_x; + auto dy = (GetY() * SCREEN_TILE_SIZE) - Game_Map::GetPositionY() - GetPanY() + screen_offset_y; - dx = Utils::PositiveModulo(dx + w / 2, w) - w / 2; - dy = Utils::PositiveModulo(dy + h / 2, h) - h / 2; + dx = Utils::PositiveModulo(dx + map_width / 2, map_width) - map_width / 2; + dy = Utils::PositiveModulo(dy + map_height / 2, map_height) - map_height / 2; + // If sx or sy equals zero, no scrolling is needed in the corresponding direction const auto sx = Utils::Signum(dx); const auto sy = Utils::Signum(dy); diff --git a/src/sprite_picture.cpp b/src/sprite_picture.cpp index 3fadea8568..98b0be803d 100644 --- a/src/sprite_picture.cpp +++ b/src/sprite_picture.cpp @@ -24,6 +24,7 @@ #include "game_windows.h" #include "player.h" #include "bitmap.h" +#include "game_map.h" Sprite_Picture::Sprite_Picture(int pic_id, Drawable::Flags flags) : Sprite(flags), @@ -106,8 +107,26 @@ void Sprite_Picture::Draw(Bitmap& dst) { } if (Player::game_config.fake_resolution.Get()) { - SetX(x + Player::menu_offset_x); - SetY(y + Player::menu_offset_y); + if (data.fixed_to_map) { + // If the picture scrolls with the map, apply the black border if the map is too small + int offset_x = 0; + int map_width = Game_Map::GetTilesX() * TILE_SIZE; + if (map_width < Player::screen_width) { + offset_x += (Player::screen_width - map_width) / 2; + } + SetX(x + offset_x); + + int offset_y = 0; + int map_height = Game_Map::GetTilesY() * TILE_SIZE; + if (map_height < Player::screen_height) { + offset_y += (Player::screen_height - map_height) / 2; + } + SetY(y + offset_y); + } else { + // If the picture doesn't scroll with the map, simulate the 340x240 screen + SetX(x + Player::menu_offset_x); + SetY(y + Player::menu_offset_y); + } } else { SetX(x); SetY(y); diff --git a/src/spriteset_map.cpp b/src/spriteset_map.cpp index 50ea8a8842..47a0f1f644 100644 --- a/src/spriteset_map.cpp +++ b/src/spriteset_map.cpp @@ -326,12 +326,16 @@ void Spriteset_Map::CalculateMapRenderOffset() { void Spriteset_Map::CalculatePanoramaRenderOffset() { // Resolution hack for Panorama + // If the map is too small to fit in the screen, add an offset corresponding to the black border's size if (Player::game_config.fake_resolution.Get()) { - if (Game_Map::Parallax::FakeXPosition()) { - panorama->SetRenderOx((Player::screen_width - SCREEN_TARGET_WIDTH) / 2); + int map_width_in_pixels = Game_Map::GetTilesX() * TILE_SIZE; + if (map_width_in_pixels < Player::screen_width) { + panorama->SetRenderOx((Player::screen_width - map_width_in_pixels) / 2); } - if (Game_Map::Parallax::FakeYPosition()) { - panorama->SetRenderOy((Player::screen_height - SCREEN_TARGET_HEIGHT) / 2); + + int map_height_in_pixels = Game_Map::GetTilesY() * TILE_SIZE; + if (map_height_in_pixels < Player::screen_height) { + panorama->SetRenderOy((Player::screen_height - map_height_in_pixels) / 2); } } }