From bf93ee664104accc446ee71d462ffb794eb2c610 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=CE=B6eh=20Matt?= Date: Wed, 2 Oct 2019 22:14:56 +0200 Subject: [PATCH] Fix #8584: Duck spawn search now uses entire map (#9743) --- distribution/changelog.txt | 1 + src/openrct2/network/Network.cpp | 2 +- src/openrct2/scenario/Scenario.cpp | 70 +++++++++++++++++------------- src/openrct2/world/Duck.cpp | 67 ++++++++++++++-------------- src/openrct2/world/Sprite.h | 2 +- 5 files changed, 78 insertions(+), 64 deletions(-) diff --git a/distribution/changelog.txt b/distribution/changelog.txt index 9ea2f23ba9c1..3cd8a5cbf851 100644 --- a/distribution/changelog.txt +++ b/distribution/changelog.txt @@ -8,6 +8,7 @@ - Fix: [#7690] Problem with guests freezing on certain tiles of path. - Fix: [#7883] Headless server log is stored incorrectly if server name contains CJK in Ubuntu - Fix: [#8136] Excessive lateral G penalty is too excessive. +- Fix: [#8584] Duck spawning function does not check tiles with x or y coordinate of 0..64 (Original bug) - Fix: [#9179] Crash when modifying a ride occasionally. - Fix: [#9533] Door sounds not playing. - Fix: [#9574] Text overflow in scenario objective window when using CJK languages. diff --git a/src/openrct2/network/Network.cpp b/src/openrct2/network/Network.cpp index 8176696298c5..515a8f1f17ba 100644 --- a/src/openrct2/network/Network.cpp +++ b/src/openrct2/network/Network.cpp @@ -34,7 +34,7 @@ // This string specifies which version of network stream current build uses. // It is used for making sure only compatible builds get connected, even within // single OpenRCT2 version. -#define NETWORK_STREAM_VERSION "16" +#define NETWORK_STREAM_VERSION "17" #define NETWORK_STREAM_ID OPENRCT2_VERSION "-" NETWORK_STREAM_VERSION static Peep* _pickup_peep = nullptr; diff --git a/src/openrct2/scenario/Scenario.cpp b/src/openrct2/scenario/Scenario.cpp index 31ba9d923662..74d49b2d0d62 100644 --- a/src/openrct2/scenario/Scenario.cpp +++ b/src/openrct2/scenario/Scenario.cpp @@ -18,6 +18,7 @@ #include "../ParkImporter.h" #include "../audio/audio.h" #include "../config/Config.h" +#include "../core/Guard.hpp" #include "../core/Random.hpp" #include "../interface/Viewport.h" #include "../localisation/Date.h" @@ -415,60 +416,69 @@ void scenario_update() } scenario_update_daynight_cycle(); } - /** * * rct2: 0x006744A9 */ static int32_t scenario_create_ducks() { - int32_t i, j, r, c, x, y, waterZ, centreWaterZ, x2, y2; + CoordsXY centrePos; + centrePos.x = 64 + (scenario_rand_max(MAXIMUM_MAP_SIZE_PRACTICAL) * 32); + centrePos.y = 64 + (scenario_rand_max(MAXIMUM_MAP_SIZE_PRACTICAL) * 32); - r = scenario_rand(); - x = ((r >> 16) & 0xFFFF) & 0x7F; - y = (r & 0xFFFF) & 0x7F; - x = (x + 64) * 32; - y = (y + 64) * 32; + Guard::Assert(map_is_location_valid(centrePos)); - if (!map_is_location_in_park({ x, y })) + if (!map_is_location_in_park(centrePos)) return 0; - centreWaterZ = (tile_element_water_height({ x, y })); + int32_t centreWaterZ = (tile_element_water_height(centrePos)); if (centreWaterZ == 0) return 0; - // Check 7x7 area around centre tile - x2 = x - (32 * 3); - y2 = y - (32 * 3); - c = 0; - for (i = 0; i < 7; i++) + // Check NxN area around centre tile defined by SquareSize + constexpr int32_t SquareSize = 7; + constexpr int32_t SquareCentre = SquareSize / 2; + + CoordsXY innerPos{ centrePos.x - (32 * SquareCentre), centrePos.y - (32 * SquareCentre) }; + int32_t waterTiles = 0; + for (int32_t y = 0; y < SquareSize; y++) { - for (j = 0; j < 7; j++) + for (int32_t x = 0; x < SquareSize; x++) { - waterZ = (tile_element_water_height({ x2, y2 })); + if (!map_is_location_valid(innerPos)) + continue; + + if (!map_is_location_in_park(innerPos)) + continue; + + int32_t waterZ = (tile_element_water_height(innerPos)); if (waterZ == centreWaterZ) - c++; + waterTiles++; - x2 += 32; + innerPos.x += 32; } - x2 -= 224; - y2 += 32; + innerPos.x -= SquareSize * 32; + innerPos.y += 32; } // Must be at least 25 water tiles of the same height in 7x7 area - if (c < 25) + if (waterTiles < 25) return 0; // Set x, y to the centre of the tile - x += 16; - y += 16; - c = (scenario_rand() & 3) + 2; - for (i = 0; i < c; i++) - { - r = scenario_rand(); - x2 = (r >> 16) & 0x7F; - y2 = (r & 0xFFFF) & 0x7F; - create_duck(x + x2 - 64, y + y2 - 64); + centrePos.x += 16; + centrePos.y += 16; + + int32_t duckCount = (scenario_rand() & 3) + 2; + for (int32_t i = 0; i < duckCount; i++) + { + int32_t r = scenario_rand(); + innerPos.x = (r >> 16) & 0x7F; + innerPos.y = (r & 0xFFFF) & 0x7F; + + CoordsXY targetPos{ centrePos.x + innerPos.x - 64, centrePos.y + innerPos.y - 64 }; + Guard::Assert(map_is_location_valid(targetPos)); + create_duck(targetPos); } return 1; diff --git a/src/openrct2/world/Duck.cpp b/src/openrct2/world/Duck.cpp index 2ac56c40fd45..c2ccc4da6ce6 100644 --- a/src/openrct2/world/Duck.cpp +++ b/src/openrct2/world/Duck.cpp @@ -305,42 +305,45 @@ uint32_t rct_duck::GetFrameImage(int32_t direction) const return imageId; } -void create_duck(int32_t targetX, int32_t targetY) +void create_duck(const CoordsXY& pos) { rct_sprite* sprite = create_sprite(SPRITE_IDENTIFIER_MISC); - if (sprite != nullptr) + if (sprite == nullptr) + return; + + CoordsXY targetPos = pos; + + int32_t offsetXY = scenario_rand() & 0x1E; + targetPos.x += offsetXY; + targetPos.y += offsetXY; + + sprite->duck.sprite_identifier = SPRITE_IDENTIFIER_MISC; + sprite->duck.type = SPRITE_MISC_DUCK; + sprite->duck.sprite_width = 9; + sprite->duck.sprite_height_negative = 12; + sprite->duck.sprite_height_positive = 9; + sprite->duck.target_x = targetPos.x; + sprite->duck.target_y = targetPos.y; + uint8_t direction = scenario_rand() & 3; + switch (direction) { - sprite->duck.sprite_identifier = SPRITE_IDENTIFIER_MISC; - sprite->duck.type = SPRITE_MISC_DUCK; - sprite->duck.sprite_width = 9; - sprite->duck.sprite_height_negative = 12; - sprite->duck.sprite_height_positive = 9; - int32_t offsetXY = scenario_rand() & 0x1E; - targetX += offsetXY; - targetY += offsetXY; - sprite->duck.target_x = targetX; - sprite->duck.target_y = targetY; - uint8_t direction = scenario_rand() & 3; - switch (direction) - { - case 0: - targetX = 8191 - (scenario_rand() & 0x3F); - break; - case 1: - targetY = scenario_rand() & 0x3F; - break; - case 2: - targetX = scenario_rand() & 0x3F; - break; - case 3: - targetY = 8191 - (scenario_rand() & 0x3F); - break; - } - sprite->duck.sprite_direction = direction << 3; - sprite_move(targetX, targetY, 496, sprite); - sprite->duck.state = DUCK_STATE::FLY_TO_WATER; - sprite->duck.frame = 0; + case 0: + targetPos.x = 8191 - (scenario_rand() & 0x3F); + break; + case 1: + targetPos.y = scenario_rand() & 0x3F; + break; + case 2: + targetPos.x = scenario_rand() & 0x3F; + break; + case 3: + targetPos.y = 8191 - (scenario_rand() & 0x3F); + break; } + sprite->duck.sprite_direction = direction << 3; + sprite_move(targetPos.x, targetPos.y, 496, sprite); + sprite->duck.state = DUCK_STATE::FLY_TO_WATER; + sprite->duck.frame = 0; } void duck_update(rct_duck* duck) diff --git a/src/openrct2/world/Sprite.h b/src/openrct2/world/Sprite.h index 235df7c0105e..b0f76e0c42d1 100644 --- a/src/openrct2/world/Sprite.h +++ b/src/openrct2/world/Sprite.h @@ -227,7 +227,7 @@ void balloon_update(rct_balloon* balloon); /////////////////////////////////////////////////////////////// // Duck /////////////////////////////////////////////////////////////// -void create_duck(int32_t targetX, int32_t targetY); +void create_duck(const CoordsXY& pos); void duck_update(rct_duck* duck); void duck_press(rct_duck* duck); void duck_remove_all();