Skip to content

Commit

Permalink
Fix #8584: Duck spawn search now uses entire map (#9743)
Browse files Browse the repository at this point in the history
  • Loading branch information
ZehMatt authored and Gymnasiast committed Oct 2, 2019
1 parent 15767c3 commit 0b95dcd
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 64 deletions.
1 change: 1 addition & 0 deletions distribution/changelog.txt
Expand Up @@ -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.
Expand Down
2 changes: 1 addition & 1 deletion src/openrct2/network/Network.cpp
Expand Up @@ -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;
Expand Down
70 changes: 40 additions & 30 deletions src/openrct2/scenario/Scenario.cpp
Expand Up @@ -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"
Expand Down Expand Up @@ -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;
Expand Down
67 changes: 35 additions & 32 deletions src/openrct2/world/Duck.cpp
Expand Up @@ -305,42 +305,45 @@ uint32_t rct_duck::GetFrameImage(int32_t direction) const
return imageId;
}

void create_duck(int32_t targetX, int32_t targetY)

This comment has been minimized.

Copy link
@chfast

chfast Nov 14, 2019

Contributor

You should pass CoordsXY by value - on 64-bit systems it will be passed in single register.
https://godbolt.org/z/Q64C-X

This comment has been minimized.

Copy link
@duncanspumpkin

duncanspumpkin Nov 14, 2019

Contributor

What about CoordsXYZ and CoordsXYZD?

This comment has been minimized.

Copy link
@chfast

chfast Nov 15, 2019

Contributor

I think it should be still fine although compilers differs there: GCC is passing by pointer (no much different than current state), clang in 2 registers directly.
https://godbolt.org/z/x9WeUq

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)
Expand Down
2 changes: 1 addition & 1 deletion src/openrct2/world/Sprite.h
Expand Up @@ -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();
Expand Down

0 comments on commit 0b95dcd

Please sign in to comment.