Merge branch 'develop'

This commit is contained in:
duncanspumpkin 2021-07-25 20:05:41 +01:00
commit f219247b19
37 changed files with 1052 additions and 919 deletions

View File

@ -171,6 +171,7 @@ The following people are not part of the development team, but have been contrib
* (zrowny)
* Emre Aydin (aemreaydin)
* Daniel Karandikar (DKarandikar)
* Struan Clark (xtruan)
## Toolchain
* (Balletie) - macOS

File diff suppressed because it is too large Load Diff

View File

@ -1,3 +1,11 @@
0.3.4+ (in development)
------------------------------------------------------------------------
- Fix: [#15028] Crash when placing large scenery.
- Fix: [#15048] Crash when removing litter with cheats.
- Fix: [#15052] Crash when using banner window.
- Fix: [#15063] Crash when opening large scenery signs.
- Improved: [#12626] Allow using RCT2 saves to mark RCT Classic (.sea) parks as finished and vice versa.
0.3.4 (2021-07-19)
------------------------------------------------------------------------
- Feature: [#13967] Track List window now displays the path to the design when debugging tools are on.

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

View File

@ -844,6 +844,18 @@
"palette": "keep",
"forceBmp": true
},
{
"path": "font/latin/oe-uc-small.png",
"y_offset": 0,
"palette": "keep",
"forceBmp": true
},
{
"path": "font/latin/oe-small.png",
"y_offset": 2,
"palette": "keep",
"forceBmp": true
},
{
"path": "font/latin/u-double-acute-uc-small.png",
"y_offset": 0,
@ -1409,6 +1421,18 @@
"palette": "keep",
"forceBmp": true
},
{
"path": "font/latin/oe-uc-bold.png",
"y_offset": 0,
"palette": "keep",
"forceBmp": true
},
{
"path": "font/latin/oe-bold.png",
"y_offset": 2,
"palette": "keep",
"forceBmp": true
},
{
"path": "font/latin/u-double-acute-uc-bold.png",
"y_offset": 0,
@ -1982,6 +2006,18 @@
"palette": "keep",
"forceBmp": true
},
{
"path": "font/latin/oe-uc-tiny.png",
"y_offset": 0,
"palette": "keep",
"forceBmp": true
},
{
"path": "font/latin/oe-tiny.png",
"y_offset": 1,
"palette": "keep",
"forceBmp": true
},
{
"path": "font/latin/u-double-acute-uc-tiny.png",
"y_offset": 0,

View File

@ -232,7 +232,7 @@ namespace OpenRCT2::Ui
return result;
}
static std::wstring GetFilterString(const std::vector<FileDialogDesc::Filter> filters)
static std::wstring GetFilterString(const std::vector<FileDialogDesc::Filter>& filters)
{
std::wstringstream filtersb;
for (const auto& filter : filters)

View File

@ -123,7 +123,7 @@ public:
~UiContext() override
{
CloseWindow();
UiContext::CloseWindow();
delete _windowManager;
SDL_QuitSubSystem(SDL_INIT_VIDEO);
delete _platformUiContext;
@ -179,11 +179,8 @@ public:
if (mode == FULLSCREEN_MODE::FULLSCREEN)
{
SDL_SetWindowFullscreen(_window, 0);
}
// Set window size
if (mode == FULLSCREEN_MODE::FULLSCREEN)
{
// Set window size
UpdateFullscreenResolutions();
Resolution resolution = GetClosestResolution(gConfigGeneral.fullscreen_width, gConfigGeneral.fullscreen_height);
SDL_SetWindowSize(_window, resolution.Width, resolution.Height);
@ -598,7 +595,7 @@ public:
{
scaleQuality = ScaleQuality::Linear;
}
snprintf(scaleQualityBuffer, sizeof(scaleQualityBuffer), "%u", static_cast<int32_t>(scaleQuality));
snprintf(scaleQualityBuffer, sizeof(scaleQualityBuffer), "%d", static_cast<int32_t>(scaleQuality));
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, scaleQualityBuffer);
int32_t width, height;

View File

@ -47,9 +47,9 @@ namespace OpenRCT2::Audio
public:
AudioChannelImpl()
{
SetRate(1);
SetVolume(MIXER_VOLUME_MAX);
SetPan(0.5f);
AudioChannelImpl::SetRate(1);
AudioChannelImpl::SetVolume(MIXER_VOLUME_MAX);
AudioChannelImpl::SetPan(0.5f);
}
~AudioChannelImpl() override

View File

@ -56,7 +56,7 @@ namespace OpenRCT2::Audio
~AudioMixerImpl() override
{
Close();
AudioMixerImpl::Close();
delete _nullSource;
}

View File

@ -134,7 +134,7 @@ public:
}
char scaleQualityBuffer[4];
snprintf(scaleQualityBuffer, sizeof(scaleQualityBuffer), "%u", static_cast<int32_t>(scaleQuality));
snprintf(scaleQualityBuffer, sizeof(scaleQualityBuffer), "%d", static_cast<int32_t>(scaleQuality));
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0");
_screenTexture = SDL_CreateTexture(_sdlRenderer, pixelFormat, SDL_TEXTUREACCESS_STREAMING, width, height);
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, scaleQualityBuffer);

View File

@ -21,9 +21,8 @@
using namespace OpenRCT2;
OpenGLShader::OpenGLShader(const char* name, GLenum type)
: _type(type)
{
_type = type;
auto path = GetPath(name);
auto sourceCode = ReadSourceCode(path);
auto sourceCodeStr = sourceCode.c_str();

View File

@ -91,9 +91,9 @@ private:
public:
Atlas(GLuint index, int32_t imageSize)
: _index(index)
, _imageSize(imageSize)
{
_index = index;
_imageSize = imageSize;
}
void Initialise(int32_t atlasWidth, int32_t atlasHeight)

View File

@ -474,7 +474,7 @@ InteractionInfo ViewportInteractionGetItemRight(const ScreenCoordsXY& screenCoor
{
ft.Add<rct_string_id>(STR_BROKEN);
}
ft.Add<rct_string_id>(pathAddEntry->name);
ft.Add<rct_string_id>(pathAddEntry != nullptr ? pathAddEntry->name : STR_NONE);
SetMapTooltip(ft);
return info;
}

View File

@ -76,7 +76,6 @@ class BannerWindow final : public Window
private:
Banner* _banner;
CoordsXYZ _bannerViewPos;
BannerElement* _bannerElement = nullptr;
void CreateViewport()
{
@ -90,24 +89,33 @@ private:
Invalidate();
}
void InitTileElement()
BannerElement* GetBannerElement()
{
TileElement* tileElement = map_get_first_element_at(_banner->position.ToCoordsXY().ToTileCentre());
if (tileElement != nullptr)
if (_banner == nullptr)
{
while (1)
{
if ((tileElement->GetType() == TILE_ELEMENT_TYPE_BANNER) && (tileElement->AsBanner()->GetIndex() == number))
{
_bannerElement = tileElement->AsBanner();
return;
}
if (tileElement->IsLastForTile())
break;
tileElement++;
}
return nullptr;
}
_bannerElement = nullptr;
TileElement* tileElement = map_get_first_element_at(_banner->position.ToCoordsXY().ToTileCentre());
if (tileElement == nullptr)
{
return nullptr;
}
do
{
auto* bannerElement = tileElement->AsBanner();
if (bannerElement == nullptr)
{
continue;
}
if (bannerElement->GetIndex() == number)
{
return bannerElement;
}
} while (!(tileElement++)->IsLastForTile());
return nullptr;
}
public:
@ -125,12 +133,11 @@ public:
number = _number;
_banner = GetBanner(number);
InitTileElement();
if (_bannerElement == nullptr)
auto* bannerElement = GetBannerElement();
if (bannerElement == nullptr)
return;
frame_no = _bannerElement->GetBaseZ();
_bannerViewPos = CoordsXYZ{ _banner->position.ToCoordsXY().ToTileCentre(), frame_no };
_bannerViewPos = CoordsXYZ{ _banner->position.ToCoordsXY().ToTileCentre(), bannerElement->GetBaseZ() };
CreateViewport();
}
@ -172,11 +179,12 @@ public:
break;
case WIDX_BANNER_DEMOLISH:
{
if (_banner == nullptr || _bannerElement == nullptr)
auto* bannerElement = GetBannerElement();
if (_banner == nullptr || bannerElement == nullptr)
break;
auto bannerRemoveAction = BannerRemoveAction(
{ _banner->position.ToCoordsXY(), _bannerElement->GetBaseZ(), _bannerElement->GetPosition() });
{ _banner->position.ToCoordsXY(), bannerElement->GetBaseZ(), bannerElement->GetPosition() });
GameActions::Execute(&bannerRemoveAction);
break;
}

View File

@ -117,13 +117,13 @@ enum
struct LoadSaveListItem
{
std::string name;
std::string path;
time_t date_modified;
std::string date_formatted;
std::string time_formatted;
uint8_t type;
bool loaded;
std::string name{};
std::string path{};
time_t date_modified{ 0 };
std::string date_formatted{};
std::string time_formatted{};
uint8_t type{ 0 };
bool loaded{ false };
};
static std::function<void(int32_t result, std::string_view)> _loadSaveCallback;

View File

@ -150,7 +150,7 @@ private:
_nextDownloadQueued = true;
}
void DownloadObject(const rct_object_entry& entry, const std::string name, const std::string url)
void DownloadObject(const rct_object_entry& entry, const std::string& name, const std::string& url)
{
try
{

View File

@ -27,8 +27,10 @@
static constexpr const rct_string_id WINDOW_TITLE = STR_SELECT_SCENARIO;
static constexpr const int32_t WW = 734;
static constexpr const int32_t WH = 334;
static constexpr const int32_t WH = 384;
static constexpr const int32_t SidebarWidth = 180;
#define INITIAL_NUM_UNLOCKED_SCENARIOS 5
constexpr const uint8_t NumTabs = 8;
// clang-format off
enum class LIST_ITEM_TYPE : uint8_t
@ -74,7 +76,7 @@ enum {
static rct_widget window_scenarioselect_widgets[] = {
WINDOW_SHIM(WINDOW_TITLE, WW, WH),
MakeWidget ({ 0, 50}, {734, 284}, WindowWidgetType::ImgBtn, WindowColour::Secondary), // tab content panel
MakeWidget ({ 0, 50}, { WW, 284}, WindowWidgetType::ImgBtn, WindowColour::Secondary), // tab content panel
MakeRemapWidget({ 3, 17}, { 91, 34}, WindowWidgetType::Tab, WindowColour::Secondary, SPR_TAB_LARGE), // tab 1
MakeRemapWidget({ 94, 17}, { 91, 34}, WindowWidgetType::Tab, WindowColour::Secondary, SPR_TAB_LARGE), // tab 2
MakeRemapWidget({185, 17}, { 91, 34}, WindowWidgetType::Tab, WindowColour::Secondary, SPR_TAB_LARGE), // tab 3
@ -83,7 +85,7 @@ static rct_widget window_scenarioselect_widgets[] = {
MakeRemapWidget({458, 17}, {136, 34}, WindowWidgetType::Tab, WindowColour::Secondary, SPR_TAB_LARGE), // tab 6
MakeRemapWidget({594, 17}, { 91, 34}, WindowWidgetType::Tab, WindowColour::Secondary, SPR_TAB_LARGE), // tab 7
MakeRemapWidget({685, 17}, { 91, 34}, WindowWidgetType::Tab, WindowColour::Secondary, SPR_TAB_LARGE), // tab 8
MakeWidget ({ 3, 54}, {553, 276}, WindowWidgetType::Scroll, WindowColour::Secondary, SCROLL_VERTICAL), // level list
MakeWidget ({ 3, 54}, { WW - SidebarWidth, 276 }, WindowWidgetType::Scroll, WindowColour::Secondary, SCROLL_VERTICAL), // level list
{ WIDGETS_END },
};
@ -140,6 +142,15 @@ static bool _showLockedInformation = false;
static bool _titleEditor = false;
static bool _disableLocking{};
static int32_t ScenarioSelectGetWindowWidth()
{
// Shrink the window if we're showing scenarios by difficulty level.
if (gConfigGeneral.scenario_select_mode == SCENARIO_SELECT_MODE_DIFFICULTY && !_titleEditor)
return 610;
else
return WW;
}
rct_window* window_scenarioselect_open(scenarioselect_callback callback, bool titleEditor)
{
if (_titleEditor != titleEditor)
@ -164,7 +175,7 @@ rct_window* window_scenarioselect_open(std::function<void(std::string_view)> cal
{
rct_window* window;
int32_t windowWidth;
int32_t windowHeight = 334;
int32_t windowHeight = WH;
_callback = callback;
_disableLocking = disableLocking;
@ -172,11 +183,7 @@ rct_window* window_scenarioselect_open(std::function<void(std::string_view)> cal
// Load scenario list
scenario_repository_scan();
// Shrink the window if we're showing scenarios by difficulty level.
if (gConfigGeneral.scenario_select_mode == SCENARIO_SELECT_MODE_DIFFICULTY && !_titleEditor)
windowWidth = 610;
else
windowWidth = 733;
windowWidth = ScenarioSelectGetWindowWidth();
window = WindowCreateCentred(
windowWidth, windowHeight, &window_scenarioselect_events, WC_SCENARIO_SELECT,
@ -237,7 +244,7 @@ static void window_scenarioselect_init_tabs(rct_window* w)
}
int32_t x = 3;
for (int32_t i = 0; i < 8; i++)
for (int32_t i = 0; i < NumTabs; i++)
{
rct_widget* widget = &w->widgets[i + WIDX_TAB1];
if (!(showPages & (1 << i)))
@ -557,8 +564,6 @@ static void window_scenarioselect_scrollpaint(rct_window* w, rct_drawpixelinfo*
rct_string_id highlighted_format = ScenarioSelectUseSmallFont() ? STR_WHITE_STRING : STR_WINDOW_COLOUR_2_STRINGID;
rct_string_id unhighlighted_format = ScenarioSelectUseSmallFont() ? STR_WHITE_STRING : STR_BLACK_STRING;
bool wide = gConfigGeneral.scenario_select_mode == SCENARIO_SELECT_MODE_ORIGIN || _titleEditor;
rct_widget* listWidget = &w->widgets[WIDX_SCENARIOLIST];
int32_t listWidth = listWidget->width() - 12;
@ -608,13 +613,17 @@ static void window_scenarioselect_scrollpaint(rct_window* w, rct_drawpixelinfo*
ft.Add<char*>(buffer);
colour_t colour = isDisabled ? w->colours[1] | COLOUR_FLAG_INSET : COLOUR_BLACK;
FontSpriteBase fontSpriteBase = isDisabled ? FontSpriteBase::MEDIUM_DARK : FontSpriteBase::MEDIUM;
DrawTextBasic(dpi, { wide ? 270 : 210, y + 1 }, format, ft, { colour, fontSpriteBase, TextAlignment::CENTRE });
const auto scrollCentre = window_scenarioselect_widgets[WIDX_SCENARIOLIST].width() / 2;
DrawTextBasic(dpi, { scrollCentre, y + 1 }, format, ft, { colour, fontSpriteBase, TextAlignment::CENTRE });
// Check if scenario is completed
if (isCompleted)
{
// Draw completion tick
gfx_draw_sprite(dpi, ImageId(SPR_MENU_CHECKMARK), { wide ? 500 : 395, y + 1 });
gfx_draw_sprite(
dpi, ImageId(SPR_MENU_CHECKMARK),
{ window_scenarioselect_widgets[WIDX_SCENARIOLIST].width() - 45, y + 1 });
// Draw completion score
const utf8* completedByName = "???";
@ -628,7 +637,7 @@ static void window_scenarioselect_scrollpaint(rct_window* w, rct_drawpixelinfo*
ft.Add<rct_string_id>(STR_STRING);
ft.Add<char*>(buffer);
DrawTextBasic(
dpi, { wide ? 270 : 210, y + scenarioTitleHeight + 1 }, format, ft,
dpi, { scrollCentre, y + scenarioTitleHeight + 1 }, format, ft,
{ FontSpriteBase::SMALL, TextAlignment::CENTRE });
}

View File

@ -102,15 +102,25 @@ public:
if (_isSmall)
{
list_information_type = tileElement->AsWall()->GetPrimaryColour();
var_492 = tileElement->AsWall()->GetSecondaryColour();
SceneryEntry = tileElement->AsWall()->GetEntryIndex();
auto* wallElement = tileElement->AsWall();
if (wallElement == nullptr)
{
return false;
}
list_information_type = wallElement->GetPrimaryColour();
var_492 = wallElement->GetSecondaryColour();
SceneryEntry = wallElement->GetEntryIndex();
}
else
{
list_information_type = tileElement->AsLargeScenery()->GetPrimaryColour();
var_492 = tileElement->AsLargeScenery()->GetSecondaryColour();
SceneryEntry = tileElement->AsLargeScenery()->GetEntryIndex();
auto* sceneryElement = tileElement->AsLargeScenery();
if (sceneryElement == nullptr)
{
return false;
}
list_information_type = sceneryElement->GetPrimaryColour();
var_492 = sceneryElement->GetSecondaryColour();
SceneryEntry = sceneryElement->GetEntryIndex();
}
// Create viewport

View File

@ -2549,9 +2549,7 @@ static money32 try_place_ghost_large_scenery(
gSceneryPlaceRotation = loc.direction;
TileElement* tileElement = lspar->tileElement;
gSceneryGhostPosition = { loc, tileElement->GetBaseZ() };
gSceneryGhostPosition = { loc, lspar->firstTileHeight };
if (lspar->GroundFlags & ELEMENT_IS_UNDERGROUND)
{
// Set underground on

View File

@ -284,12 +284,12 @@ GameActions::Result::Ptr LargeSceneryPlaceAction::Execute() const
SetNewLargeSceneryElement(*newSceneryElement, tileNum);
map_animation_create(MAP_ANIMATION_TYPE_LARGE_SCENERY, { curTile, zLow });
map_invalidate_tile_full(curTile);
if (tileNum == 0)
{
res->tileElement = newSceneryElement->as<TileElement>();
res->firstTileHeight = zLow;
}
map_invalidate_tile_full(curTile);
}
// Allocate banner after all tiles to ensure banner id doesn't need to be freed.

View File

@ -22,7 +22,7 @@ public:
LargeSceneryPlaceActionResult(GameActions::Status error, rct_string_id message, uint8_t* args);
uint8_t GroundFlags{ 0 };
TileElement* tileElement = nullptr;
int32_t firstTileHeight{ 0 };
};
DEFINE_GAME_ACTION(LargeSceneryPlaceAction, GameCommand::PlaceLargeScenery, LargeSceneryPlaceActionResult)

View File

@ -417,20 +417,20 @@ void SetCheatAction::RemoveLitter() const
sprite_remove(litter);
}
tile_element_iterator it;
tile_element_iterator it{};
tile_element_iterator_begin(&it);
do
{
if (it.element->GetType() != TILE_ELEMENT_TYPE_PATH)
continue;
if (!(it.element)->AsPath()->HasAddition())
auto* path = it.element->AsPath();
if (path->HasAddition())
continue;
auto* pathBitEntry = it.element->AsPath()->GetAdditionEntry();
if (pathBitEntry->flags & PATH_BIT_FLAG_IS_BIN)
it.element->AsPath()->SetAdditionStatus(0xFF);
auto* pathBitEntry = path->GetAdditionEntry();
if (pathBitEntry != nullptr && pathBitEntry->flags & PATH_BIT_FLAG_IS_BIN)
path->SetAdditionStatus(0xFF);
} while (tile_element_iterator_next(&it));

View File

@ -64,6 +64,8 @@ static const std::unordered_map<char32_t, int32_t> codepointOffsetMap = {
{ UnicodeChar::o_macron, CSChar::o_circumflex - CS_SPRITE_FONT_OFFSET }, // No visual difference
{ UnicodeChar::o_double_acute_uc, SPR_G2_O_DOUBLE_ACUTE_UPPER - SPR_CHAR_START },
{ UnicodeChar::o_double_acute, SPR_G2_O_DOUBLE_ACUTE_LOWER - SPR_CHAR_START },
{ UnicodeChar::oe_uc, SPR_G2_OE_UPPER - SPR_CHAR_START },
{ UnicodeChar::oe, SPR_G2_OE_LOWER - SPR_CHAR_START },
{ UnicodeChar::r_caron_uc, SPR_G2_R_CARON_UPPER - SPR_CHAR_START },
{ UnicodeChar::r_caron, SPR_G2_R_CARON_LOWER - SPR_CHAR_START },
{ UnicodeChar::s_acute_uc, CSChar::s_acute_uc - CS_SPRITE_FONT_OFFSET },
@ -177,6 +179,7 @@ static const std::unordered_map<char32_t, int32_t> codepointOffsetMap = {
{ UnicodeChar::interpunct, SPR_G2_INTERPUNCT - SPR_CHAR_START },
{ UnicodeChar::multiplication_sign, CSChar::cross - CS_SPRITE_FONT_OFFSET },
{ UnicodeChar::en_dash, '-' - CS_SPRITE_FONT_OFFSET },
{ UnicodeChar::em_dash, '-' - CS_SPRITE_FONT_OFFSET },
{ UnicodeChar::single_quote_open, '`' - CS_SPRITE_FONT_OFFSET },
{ UnicodeChar::single_quote_end, '\'' - CS_SPRITE_FONT_OFFSET },
{ UnicodeChar::single_german_quote_open, ',' - CS_SPRITE_FONT_OFFSET },

View File

@ -174,6 +174,8 @@ namespace UnicodeChar
constexpr char32_t o_macron = 0x14D;
constexpr char32_t o_double_acute_uc = 0x150;
constexpr char32_t o_double_acute = 0x151;
constexpr char32_t oe_uc = 0x152;
constexpr char32_t oe = 0x153;
constexpr char32_t r_caron_uc = 0x158;
constexpr char32_t r_caron = 0x159;
constexpr char32_t s_acute_uc = 0x15A;
@ -282,6 +284,7 @@ namespace UnicodeChar
constexpr char32_t interpunct = 0xB7;
constexpr char32_t multiplication_sign = 0xD7;
constexpr char32_t en_dash = 0x2013;
constexpr char32_t em_dash = 0x2014;
constexpr char32_t single_quote_open = 0x2018;
constexpr char32_t single_quote_end = 0x2019;
constexpr char32_t single_german_quote_open = 0x201A;

View File

@ -631,11 +631,11 @@ public:
private:
explicit TcpSocket(SOCKET socket, const std::string& hostName, const std::string& ipAddress)
: _status(SocketStatus::Connected)
, _socket(socket)
, _ipAddress(ipAddress)
, _hostName(hostName)
{
_socket = socket;
_hostName = hostName;
_ipAddress = ipAddress;
_status = SocketStatus::Connected;
}
void CloseSocket()
@ -833,10 +833,10 @@ public:
private:
explicit UdpSocket(SOCKET socket, const std::string& hostName)
: _status(SocketStatus::Connected)
, _socket(socket)
, _hostName(hostName)
{
_socket = socket;
_hostName = hostName;
_status = SocketStatus::Connected;
}
SOCKET CreateSocket()

View File

@ -52,7 +52,7 @@ const wchar_t* _wszCommitSha1Short = WSZ("");
// OPENRCT2_ARCHITECTURE is required to be defined in version.h
const wchar_t* _wszArchitecture = WSZ(OPENRCT2_ARCHITECTURE);
# define BACKTRACE_TOKEN L"3c7c2c6de378d59819d6755369f4d099bfe1a0d990b065f2ae427ab096cd6f40"
# define BACKTRACE_TOKEN L"742b8d9d70c52df663e4f2449f90039cf9406f89e57ecb90b0f086ba16e33d20"
// Note: uploading gzipped crash dumps manually requires specifying
// 'Content-Encoding: gzip' header in HTTP request, but we cannot do that,

View File

@ -3894,6 +3894,91 @@ void Vehicle::UpdateTravelling()
sub_state = 1;
}
void Vehicle::UpdateArrivingPassThroughStation(
const Ride& curRide, const rct_ride_entry_vehicle& vehicleEntry, bool stationBrakesWork)
{
if (sub_state == 0)
{
if (curRide.mode == RideMode::Race && curRide.lifecycle_flags & RIDE_LIFECYCLE_PASS_STATION_NO_STOPPING)
{
return;
}
if (velocity <= 131940)
{
acceleration = 3298;
return;
}
int32_t velocity_diff = velocity;
if (velocity_diff >= 1572864)
velocity_diff /= 8;
else
velocity_diff /= 16;
if (!stationBrakesWork)
{
return;
}
if (curRide.num_circuits != 1)
{
if (num_laps + 1 < curRide.num_circuits)
{
return;
}
}
velocity -= velocity_diff;
acceleration = 0;
}
else
{
if (!(vehicleEntry.flags & VEHICLE_ENTRY_FLAG_POWERED) && velocity >= -131940)
{
acceleration = -3298;
}
if (velocity >= -131940)
{
return;
}
int32_t velocity_diff = velocity;
if (velocity_diff < -1572864)
velocity_diff /= 8;
else
velocity_diff /= 16;
if (!stationBrakesWork)
{
return;
}
if (num_laps + 1 < curRide.num_circuits)
{
return;
}
if (num_laps + 1 != curRide.num_circuits)
{
velocity -= velocity_diff;
acceleration = 0;
return;
}
if (GetRideTypeDescriptor(curRide.type).HasFlag(RIDE_TYPE_FLAG_ALLOW_MULTIPLE_CIRCUITS)
&& curRide.mode != RideMode::Shuttle && curRide.mode != RideMode::PoweredLaunch)
{
SetUpdateFlag(VEHICLE_UPDATE_FLAG_12);
}
else
{
velocity -= velocity_diff;
acceleration = 0;
}
}
}
/**
*
* rct2: 0x006D8C36
@ -3904,7 +3989,7 @@ void Vehicle::UpdateArriving()
if (curRide == nullptr)
return;
uint8_t unkF64E35 = 1;
bool stationBrakesWork = true;
uint32_t curFlags = 0;
switch (curRide->mode)
@ -3942,102 +4027,22 @@ void Vehicle::UpdateArriving()
if (hasBrakesFailure && curRide->inspection_station == current_station
&& curRide->mechanic_status != RIDE_MECHANIC_STATUS_HAS_FIXED_STATION_BRAKES)
{
unkF64E35 = 0;
stationBrakesWork = false;
}
rct_ride_entry* rideEntry = GetRideEntry();
rct_ride_entry_vehicle* vehicleEntry = &rideEntry->vehicles[vehicle_type];
if (sub_state == 0)
{
if (curRide->mode == RideMode::Race && curRide->lifecycle_flags & RIDE_LIFECYCLE_PASS_STATION_NO_STOPPING)
{
goto loc_6D8E36;
}
UpdateArrivingPassThroughStation(*curRide, *vehicleEntry, stationBrakesWork);
if (velocity <= 131940)
{
acceleration = 3298;
goto loc_6D8E36;
}
int32_t velocity_diff = velocity;
if (velocity_diff >= 1572864)
velocity_diff /= 8;
else
velocity_diff /= 16;
if (unkF64E35 == 0)
{
goto loc_6D8E36;
}
if (curRide->num_circuits != 1)
{
if (num_laps + 1 < curRide->num_circuits)
{
goto loc_6D8E36;
}
}
velocity -= velocity_diff;
acceleration = 0;
}
else
{
if (!(vehicleEntry->flags & VEHICLE_ENTRY_FLAG_POWERED) && velocity >= -131940)
{
acceleration = -3298;
}
if (velocity >= -131940)
{
goto loc_6D8E36;
}
int32_t velocity_diff = velocity;
if (velocity_diff < -1572864)
velocity_diff /= 8;
else
velocity_diff /= 16;
if (unkF64E35 == 0)
{
goto loc_6D8E36;
}
if (num_laps + 1 < curRide->num_circuits)
{
goto loc_6D8E36;
}
if (num_laps + 1 != curRide->num_circuits)
{
velocity -= velocity_diff;
acceleration = 0;
goto loc_6D8E36;
}
if (GetRideTypeDescriptor(curRide->type).HasFlag(RIDE_TYPE_FLAG_ALLOW_MULTIPLE_CIRCUITS)
&& curRide->mode != RideMode::Shuttle && curRide->mode != RideMode::PoweredLaunch)
{
SetUpdateFlag(VEHICLE_UPDATE_FLAG_12);
}
else
{
velocity -= velocity_diff;
acceleration = 0;
}
}
loc_6D8E36:
curFlags = UpdateTrackMotion(nullptr);
if (curFlags & VEHICLE_UPDATE_MOTION_TRACK_FLAG_VEHICLE_COLLISION && unkF64E35 == 0)
if (curFlags & VEHICLE_UPDATE_MOTION_TRACK_FLAG_VEHICLE_COLLISION && !stationBrakesWork)
{
UpdateCollisionSetup();
return;
}
if (curFlags & VEHICLE_UPDATE_MOTION_TRACK_FLAG_VEHICLE_AT_STATION && unkF64E35 == 0)
if (curFlags & VEHICLE_UPDATE_MOTION_TRACK_FLAG_VEHICLE_AT_STATION && !stationBrakesWork)
{
SetState(Vehicle::Status::Departing, 1);
return;
@ -8545,140 +8550,142 @@ bool Vehicle::UpdateTrackMotionBackwards(rct_ride_entry_vehicle* vehicleEntry, R
{
uint16_t otherVehicleIndex = SPRITE_INDEX_NULL;
loc_6DBA33:;
auto trackType = GetTrackType();
if (trackType == TrackElemType::Flat && curRide->type == RIDE_TYPE_REVERSE_FREEFALL_COASTER)
while (true)
{
int32_t unkVelocity = _vehicleVelocityF64E08;
if (unkVelocity < -524288)
auto trackType = GetTrackType();
if (trackType == TrackElemType::Flat && curRide->type == RIDE_TYPE_REVERSE_FREEFALL_COASTER)
{
unkVelocity = abs(unkVelocity);
acceleration = unkVelocity * 2;
}
}
if (trackType == TrackElemType::Brakes)
{
if (-(brake_speed << 16) > _vehicleVelocityF64E08)
{
acceleration = _vehicleVelocityF64E08 * -16;
}
}
if (trackType == TrackElemType::Booster)
{
auto boosterSpeed = get_booster_speed(curRide->type, (brake_speed << 16));
if (boosterSpeed < _vehicleVelocityF64E08)
{
acceleration = GetRideTypeDescriptor(curRide->type).OperatingSettings.BoosterAcceleration << 16;
}
}
uint16_t newTrackProgress = track_progress - 1;
if (newTrackProgress == 0xFFFF)
{
UpdateCrossings();
if (!UpdateTrackMotionBackwardsGetNewTrack(trackType, curRide, &newTrackProgress))
{
_vehicleMotionTrackFlags |= VEHICLE_UPDATE_MOTION_TRACK_FLAG_5;
_vehicleVelocityF64E0C -= remaining_distance - 0x368A;
remaining_distance = 0x368A;
return false;
}
}
// loc_6DBD42
track_progress = newTrackProgress;
uint8_t moveInfoVehicleSpriteType;
{
const rct_vehicle_info* moveInfo = GetMoveInfo();
auto loc = TrackLocation
+ CoordsXYZ{ moveInfo->x, moveInfo->y, moveInfo->z + GetRideTypeDescriptor(curRide->type).Heights.VehicleZOffset };
uint8_t remainingDistanceFlags = 0;
if (loc.x != unk_F64E20.x)
{
remainingDistanceFlags |= 1;
}
if (loc.y != unk_F64E20.y)
{
remainingDistanceFlags |= 2;
}
if (loc.z != unk_F64E20.z)
{
remainingDistanceFlags |= 4;
}
remaining_distance += dword_9A2930[remainingDistanceFlags];
unk_F64E20 = loc;
sprite_direction = moveInfo->direction;
bank_rotation = moveInfo->bank_rotation;
Pitch = moveInfo->Pitch;
moveInfoVehicleSpriteType = moveInfo->Pitch;
if ((vehicleEntry->flags & VEHICLE_ENTRY_FLAG_WOODEN_WILD_MOUSE_SWING) && Pitch != 0)
{
SwingSprite = 0;
SwingPosition = 0;
SwingSpeed = 0;
}
if (this == _vehicleFrontVehicle)
{
if (_vehicleVelocityF64E08 < 0)
int32_t unkVelocity = _vehicleVelocityF64E08;
if (unkVelocity < -524288)
{
otherVehicleIndex = next_vehicle_on_ride;
if (UpdateMotionCollisionDetection(loc, &otherVehicleIndex))
unkVelocity = abs(unkVelocity);
acceleration = unkVelocity * 2;
}
}
if (trackType == TrackElemType::Brakes)
{
if (-(brake_speed << 16) > _vehicleVelocityF64E08)
{
acceleration = _vehicleVelocityF64E08 * -16;
}
}
if (trackType == TrackElemType::Booster)
{
auto boosterSpeed = get_booster_speed(curRide->type, (brake_speed << 16));
if (boosterSpeed < _vehicleVelocityF64E08)
{
acceleration = GetRideTypeDescriptor(curRide->type).OperatingSettings.BoosterAcceleration << 16;
}
}
uint16_t newTrackProgress = track_progress - 1;
if (newTrackProgress == 0xFFFF)
{
UpdateCrossings();
if (!UpdateTrackMotionBackwardsGetNewTrack(trackType, curRide, &newTrackProgress))
{
_vehicleMotionTrackFlags |= VEHICLE_UPDATE_MOTION_TRACK_FLAG_5;
_vehicleVelocityF64E0C -= remaining_distance - 0x368A;
remaining_distance = 0x368A;
return false;
}
}
// loc_6DBD42
track_progress = newTrackProgress;
uint8_t moveInfoVehicleSpriteType;
{
const rct_vehicle_info* moveInfo = GetMoveInfo();
auto loc = TrackLocation
+ CoordsXYZ{ moveInfo->x, moveInfo->y,
moveInfo->z + GetRideTypeDescriptor(curRide->type).Heights.VehicleZOffset };
uint8_t remainingDistanceFlags = 0;
if (loc.x != unk_F64E20.x)
{
remainingDistanceFlags |= 1;
}
if (loc.y != unk_F64E20.y)
{
remainingDistanceFlags |= 2;
}
if (loc.z != unk_F64E20.z)
{
remainingDistanceFlags |= 4;
}
remaining_distance += dword_9A2930[remainingDistanceFlags];
unk_F64E20 = loc;
sprite_direction = moveInfo->direction;
bank_rotation = moveInfo->bank_rotation;
Pitch = moveInfo->Pitch;
moveInfoVehicleSpriteType = moveInfo->Pitch;
if ((vehicleEntry->flags & VEHICLE_ENTRY_FLAG_WOODEN_WILD_MOUSE_SWING) && Pitch != 0)
{
SwingSprite = 0;
SwingPosition = 0;
SwingSpeed = 0;
}
if (this == _vehicleFrontVehicle)
{
if (_vehicleVelocityF64E08 < 0)
{
_vehicleVelocityF64E0C -= remaining_distance - 0x368A;
remaining_distance = 0x368A;
Vehicle* v3 = GetEntity<Vehicle>(otherVehicleIndex);
Vehicle* v4 = gCurrentVehicle;
if (v3 == nullptr)
otherVehicleIndex = next_vehicle_on_ride;
if (UpdateMotionCollisionDetection(loc, &otherVehicleIndex))
{
return false;
}
_vehicleVelocityF64E0C -= remaining_distance - 0x368A;
remaining_distance = 0x368A;
if (!(rideEntry->flags & RIDE_ENTRY_FLAG_DISABLE_COLLISION_CRASHES))
{
if (abs(v4->velocity - v3->velocity) > 0xE0000)
Vehicle* v3 = GetEntity<Vehicle>(otherVehicleIndex);
Vehicle* v4 = gCurrentVehicle;
if (v3 == nullptr)
{
if (!(vehicleEntry->flags & VEHICLE_ENTRY_FLAG_BOAT_HIRE_COLLISION_DETECTION))
return false;
}
if (!(rideEntry->flags & RIDE_ENTRY_FLAG_DISABLE_COLLISION_CRASHES))
{
if (abs(v4->velocity - v3->velocity) > 0xE0000)
{
_vehicleMotionTrackFlags |= VEHICLE_UPDATE_MOTION_TRACK_FLAG_VEHICLE_COLLISION;
if (!(vehicleEntry->flags & VEHICLE_ENTRY_FLAG_BOAT_HIRE_COLLISION_DETECTION))
{
_vehicleMotionTrackFlags |= VEHICLE_UPDATE_MOTION_TRACK_FLAG_VEHICLE_COLLISION;
}
}
}
}
if (vehicleEntry->flags & VEHICLE_ENTRY_FLAG_GO_KART)
{
velocity -= velocity >> 2;
_vehicleMotionTrackFlags |= VEHICLE_UPDATE_MOTION_TRACK_FLAG_2;
}
else
{
int32_t v3Velocity = v3->velocity;
v3->velocity = v4->velocity >> 1;
v4->velocity = v3Velocity >> 1;
_vehicleMotionTrackFlags |= VEHICLE_UPDATE_MOTION_TRACK_FLAG_2;
}
if (vehicleEntry->flags & VEHICLE_ENTRY_FLAG_GO_KART)
{
velocity -= velocity >> 2;
_vehicleMotionTrackFlags |= VEHICLE_UPDATE_MOTION_TRACK_FLAG_2;
}
else
{
int32_t v3Velocity = v3->velocity;
v3->velocity = v4->velocity >> 1;
v4->velocity = v3Velocity >> 1;
_vehicleMotionTrackFlags |= VEHICLE_UPDATE_MOTION_TRACK_FLAG_2;
}
return false;
return false;
}
}
}
}
}
// loc_6DBE3F
if (remaining_distance >= 0)
{
return true;
// loc_6DBE3F
if (remaining_distance >= 0)
{
return true;
}
acceleration += dword_9A2970[moveInfoVehicleSpriteType];
_vehicleUnkF64E10++;
}
acceleration += dword_9A2970[moveInfoVehicleSpriteType];
_vehicleUnkF64E10++;
goto loc_6DBA33;
}
/**
@ -9219,6 +9226,83 @@ static constexpr int32_t GetAccelerationDecrease2(const int32_t velocity, const
}
}
int32_t Vehicle::UpdateTrackMotionMiniGolfCalculateAcceleration(const rct_ride_entry_vehicle& vehicleEntry)
{
int32_t sumAcceleration = 0;
int32_t numVehicles = 0;
uint16_t totalMass = 0;
for (Vehicle* vehicle = this; vehicle != nullptr; vehicle = GetEntity<Vehicle>(vehicle->next_vehicle_on_train))
{
numVehicles++;
totalMass += vehicle->mass;
sumAcceleration += vehicle->acceleration;
}
int32_t newAcceleration = ((sumAcceleration / numVehicles) * 21) >> 9;
newAcceleration -= velocity >> 12;
newAcceleration -= GetAccelerationDecrease2(velocity, totalMass);
if (!(vehicleEntry.flags & VEHICLE_ENTRY_FLAG_POWERED))
{
return newAcceleration;
}
if (vehicleEntry.flags & VEHICLE_ENTRY_FLAG_POWERED_RIDE_UNRESTRICTED_GRAVITY)
{
if (speed * 0x4000 < velocity)
{
return newAcceleration;
}
}
{
int32_t poweredAcceleration = speed << 14;
int32_t quarterForce = (speed * totalMass) >> 2;
if (HasUpdateFlag(VEHICLE_UPDATE_FLAG_REVERSING_SHUTTLE))
{
poweredAcceleration = -poweredAcceleration;
}
poweredAcceleration -= velocity;
poweredAcceleration *= powered_acceleration << 1;
if (quarterForce != 0)
poweredAcceleration /= quarterForce;
if (vehicleEntry.flags & VEHICLE_ENTRY_FLAG_WATER_RIDE)
{
if (poweredAcceleration < 0)
{
poweredAcceleration >>= 4;
}
if (vehicleEntry.flags & VEHICLE_ENTRY_FLAG_SPINNING)
{
spin_speed = std::clamp(spin_speed, VEHICLE_MIN_SPIN_SPEED_WATER_RIDE, VEHICLE_MAX_SPIN_SPEED_WATER_RIDE);
}
if (Pitch != 0)
{
poweredAcceleration = std::max(0, poweredAcceleration);
if (vehicleEntry.flags & VEHICLE_ENTRY_FLAG_SPINNING)
{
if (Pitch == 2)
{
spin_speed = 0;
}
}
newAcceleration += poweredAcceleration;
return newAcceleration;
}
}
if (abs(velocity) > 0x10000)
{
newAcceleration = 0;
}
newAcceleration += poweredAcceleration;
}
return newAcceleration;
}
int32_t Vehicle::UpdateTrackMotionMiniGolf(int32_t* outStation)
{
auto curRide = GetRide();
@ -9262,79 +9346,7 @@ int32_t Vehicle::UpdateTrackMotionMiniGolf(int32_t* outStation)
}
}
int32_t sumAcceleration = 0;
int32_t numVehicles = 0;
uint16_t totalMass = 0;
for (Vehicle* vehicle = this; vehicle != nullptr; vehicle = GetEntity<Vehicle>(vehicle->next_vehicle_on_train))
{
numVehicles++;
totalMass += vehicle->mass;
sumAcceleration += vehicle->acceleration;
}
int32_t newAcceleration = ((sumAcceleration / numVehicles) * 21) >> 9;
newAcceleration -= velocity >> 12;
newAcceleration -= GetAccelerationDecrease2(velocity, totalMass);
if (!(vehicleEntry->flags & VEHICLE_ENTRY_FLAG_POWERED))
{
goto loc_6DD069;
}
if (vehicleEntry->flags & VEHICLE_ENTRY_FLAG_POWERED_RIDE_UNRESTRICTED_GRAVITY)
{
if (speed * 0x4000 < velocity)
{
goto loc_6DD069;
}
}
{
int32_t poweredAcceleration = speed << 14;
int32_t quarterForce = (speed * totalMass) >> 2;
if (HasUpdateFlag(VEHICLE_UPDATE_FLAG_REVERSING_SHUTTLE))
{
poweredAcceleration = -poweredAcceleration;
}
poweredAcceleration -= velocity;
poweredAcceleration *= powered_acceleration << 1;
if (quarterForce != 0)
poweredAcceleration /= quarterForce;
if (vehicleEntry->flags & VEHICLE_ENTRY_FLAG_WATER_RIDE)
{
if (poweredAcceleration < 0)
{
poweredAcceleration >>= 4;
}
if (vehicleEntry->flags & VEHICLE_ENTRY_FLAG_SPINNING)
{
spin_speed = std::clamp(spin_speed, VEHICLE_MIN_SPIN_SPEED_WATER_RIDE, VEHICLE_MAX_SPIN_SPEED_WATER_RIDE);
}
if (Pitch != 0)
{
poweredAcceleration = std::max(0, poweredAcceleration);
if (vehicleEntry->flags & VEHICLE_ENTRY_FLAG_SPINNING)
{
if (Pitch == 2)
{
spin_speed = 0;
}
}
newAcceleration += poweredAcceleration;
goto loc_6DD069;
}
}
if (abs(velocity) > 0x10000)
{
newAcceleration = 0;
}
newAcceleration += poweredAcceleration;
}
loc_6DD069:
acceleration = newAcceleration;
acceleration = UpdateTrackMotionMiniGolfCalculateAcceleration(*vehicleEntry);
if (outStation != nullptr)
*outStation = _vehicleStationIndex;

View File

@ -308,6 +308,8 @@ private:
void UpdateDepartingBoatHire();
void UpdateTravellingBoatHireSetup();
void UpdateBoatLocation();
void UpdateArrivingPassThroughStation(
const Ride& curRide, const rct_ride_entry_vehicle& vehicleEntry, bool stationBrakesWork);
void UpdateArriving();
void UpdateUnloadingPassengers();
void UpdateWaitingForCableLift();
@ -354,6 +356,7 @@ private:
void KillAllPassengersInTrain();
void KillPassengers(Ride* curRide);
void TrainReadyToDepart(uint8_t num_peeps_on_train, uint8_t num_used_seats);
int32_t UpdateTrackMotionMiniGolfCalculateAcceleration(const rct_ride_entry_vehicle& vehicleEntry);
int32_t UpdateTrackMotionMiniGolf(int32_t* outStation);
void UpdateTrackMotionMiniGolfVehicle(Ride* curRide, rct_ride_entry* rideEntry, rct_ride_entry_vehicle* vehicleEntry);
bool UpdateTrackMotionForwardsGetNewTrack(uint16_t trackType, Ride* curRide, rct_ride_entry* rideEntry);

View File

@ -423,6 +423,25 @@ public:
Scan(language);
scenario_index_entry* scenario = GetByFilename(scenarioFileName);
// Check if this is an RCTC scenario that corresponds to a known RCT1/2 scenario or vice versa, see #12626
if (scenario == nullptr)
{
const std::string scenarioBaseName = String::ToStd(Path::GetFileNameWithoutExtension(scenarioFileName));
const std::string scenarioExtension = String::ToStd(Path::GetExtension(scenarioFileName));
if (String::Equals(scenarioExtension, ".sea", true))
{
// Get scenario using RCT2 style name of RCTC scenario
scenario = GetByFilename((scenarioBaseName + ".sc6").c_str());
}
else if (String::Equals(scenarioExtension, ".sc6", true))
{
// Get scenario using RCTC style name of RCT2 scenario
scenario = GetByFilename((scenarioBaseName + ".sea").c_str());
}
}
if (scenario != nullptr)
{
// Check if record company value has been broken or the highscore is the same but no name is registered
@ -705,10 +724,10 @@ private:
{
for (auto& highscore : _highscores)
{
scenario_index_entry* scenerio = GetByFilename(highscore->fileName);
if (scenerio != nullptr)
scenario_index_entry* scenario = GetByFilename(highscore->fileName);
if (scenario != nullptr)
{
scenerio->highscore = highscore;
scenario->highscore = highscore;
}
}
}

View File

@ -946,30 +946,34 @@ enum
SPR_G2_O_DOUBLE_ACUTE_UPPER = SPR_G2_CHAR_BEGIN + 66,
SPR_G2_O_DOUBLE_ACUTE_LOWER = SPR_G2_CHAR_BEGIN + 67,
SPR_G2_U_DOUBLE_ACUTE_UPPER = SPR_G2_CHAR_BEGIN + 68,
SPR_G2_U_DOUBLE_ACUTE_LOWER = SPR_G2_CHAR_BEGIN + 69,
SPR_G2_D_CARON_UPPER = SPR_G2_CHAR_BEGIN + 70,
SPR_G2_D_CARON_LOWER = SPR_G2_CHAR_BEGIN + 71,
SPR_G2_E_CARON_UPPER = SPR_G2_CHAR_BEGIN + 72,
SPR_G2_E_CARON_LOWER = SPR_G2_CHAR_BEGIN + 73,
SPR_G2_N_CARON_UPPER = SPR_G2_CHAR_BEGIN + 74,
SPR_G2_N_CARON_LOWER = SPR_G2_CHAR_BEGIN + 75,
SPR_G2_R_CARON_UPPER = SPR_G2_CHAR_BEGIN + 76,
SPR_G2_R_CARON_LOWER = SPR_G2_CHAR_BEGIN + 77,
SPR_G2_S_CARON_UPPER = SPR_G2_CHAR_BEGIN + 78,
SPR_G2_S_CARON_LOWER = SPR_G2_CHAR_BEGIN + 79,
SPR_G2_T_CARON_UPPER = SPR_G2_CHAR_BEGIN + 80,
SPR_G2_T_CARON_LOWER = SPR_G2_CHAR_BEGIN + 81,
SPR_G2_U_RING_UPPER = SPR_G2_CHAR_BEGIN + 82,
SPR_G2_U_RING_LOWER = SPR_G2_CHAR_BEGIN + 83,
SPR_G2_Z_CARON_UPPER = SPR_G2_CHAR_BEGIN + 84,
SPR_G2_Z_CARON_LOWER = SPR_G2_CHAR_BEGIN + 85,
SPR_G2_OE_UPPER,
SPR_G2_OE_LOWER,
SPR_G2_ROUBLE_SIGN = SPR_G2_CHAR_BEGIN + 86,
SPR_G2_U_DOUBLE_ACUTE_UPPER,
SPR_G2_U_DOUBLE_ACUTE_LOWER,
SPR_G2_J = SPR_G2_CHAR_BEGIN + 87,
SPR_G2_L = SPR_G2_CHAR_BEGIN + 88,
SPR_G2_D_CARON_UPPER,
SPR_G2_D_CARON_LOWER,
SPR_G2_E_CARON_UPPER,
SPR_G2_E_CARON_LOWER,
SPR_G2_N_CARON_UPPER,
SPR_G2_N_CARON_LOWER,
SPR_G2_R_CARON_UPPER,
SPR_G2_R_CARON_LOWER,
SPR_G2_S_CARON_UPPER,
SPR_G2_S_CARON_LOWER,
SPR_G2_T_CARON_UPPER,
SPR_G2_T_CARON_LOWER,
SPR_G2_U_RING_UPPER,
SPR_G2_U_RING_LOWER,
SPR_G2_Z_CARON_UPPER,
SPR_G2_Z_CARON_LOWER,
SPR_G2_ROUBLE_SIGN,
SPR_G2_J,
SPR_G2_L,
SPR_G2_C_CIRCUMFLEX_UPPER,
SPR_G2_C_CIRCUMFLEX_LOWER,

View File

@ -1302,6 +1302,39 @@ void map_obstruction_set_error_text(TileElement* tileElement, GameActions::Resul
}
}
static bool MapLoc68BABCShouldContinue(
TileElement* tileElement, const CoordsXYRangedZ& pos, CLEAR_FUNC clearFunc, uint8_t flags, money32& price,
uint8_t crossingMode, bool canBuildCrossing)
{
if (clearFunc != nullptr)
{
if (!clearFunc(&tileElement, pos, flags, &price))
{
return true;
}
}
// Crossing mode 1: building track over path
if (crossingMode == 1 && canBuildCrossing && tileElement->GetType() == TILE_ELEMENT_TYPE_PATH
&& tileElement->GetBaseZ() == pos.baseZ && !tileElement->AsPath()->IsQueue() && !tileElement->AsPath()->IsSloped())
{
return true;
}
// Crossing mode 2: building path over track
else if (
crossingMode == 2 && canBuildCrossing && tileElement->GetType() == TILE_ELEMENT_TYPE_TRACK
&& tileElement->GetBaseZ() == pos.baseZ && tileElement->AsTrack()->GetTrackType() == TrackElemType::Flat)
{
auto ride = get_ride(tileElement->AsTrack()->GetRideIndex());
if (ride != nullptr && ride->GetRideTypeDescriptor().HasFlag(RIDE_TYPE_FLAG_SUPPORTS_LEVEL_CROSSINGS))
{
return true;
}
}
return false;
}
/**
*
* rct2: 0x0068B932
@ -1350,7 +1383,18 @@ std::unique_ptr<GameActions::ConstructClearResult> MapCanConstructWithClearAt(
{
if (tileElement->GetOccupiedQuadrants() & (quarterTile.GetBaseQuarterOccupied()))
{
goto loc_68BABC;
if (MapLoc68BABCShouldContinue(
tileElement, pos, clearFunc, flags, res->Cost, crossingMode, canBuildCrossing))
{
continue;
}
if (tileElement != nullptr)
{
map_obstruction_set_error_text(tileElement, *res);
res->Error = GameActions::Status::NoClearance;
}
return res;
}
}
continue;
@ -1361,10 +1405,26 @@ std::unique_ptr<GameActions::ConstructClearResult> MapCanConstructWithClearAt(
res->GroundFlags |= ELEMENT_IS_UNDERWATER;
if (water_height < pos.clearanceZ)
{
goto loc_68BAE6;
bool returnError = true;
if (clearFunc != nullptr)
{
if (!clearFunc(&tileElement, pos, flags, &res->Cost))
{
returnError = false;
}
}
if (returnError)
{
if (tileElement != nullptr)
{
res->Error = GameActions::Status::NoClearance;
res->ErrorMessage = STR_CANNOT_BUILD_PARTLY_ABOVE_AND_PARTLY_BELOW_WATER;
}
return res;
}
}
}
loc_68B9B7:
if (gParkFlags & PARK_FLAGS_FORBID_HIGH_CONSTRUCTION && !isTree)
{
auto heightFromGround = pos.clearanceZ - tileElement->GetBaseZ();
@ -1435,33 +1495,11 @@ std::unique_ptr<GameActions::ConstructClearResult> MapCanConstructWithClearAt(
continue;
}
}
loc_68BABC:
if (clearFunc != nullptr)
{
if (!clearFunc(&tileElement, pos, flags, &res->Cost))
{
continue;
}
}
// Crossing mode 1: building track over path
if (crossingMode == 1 && canBuildCrossing && tileElement->GetType() == TILE_ELEMENT_TYPE_PATH
&& tileElement->GetBaseZ() == pos.baseZ && !tileElement->AsPath()->IsQueue()
&& !tileElement->AsPath()->IsSloped())
if (MapLoc68BABCShouldContinue(tileElement, pos, clearFunc, flags, res->Cost, crossingMode, canBuildCrossing))
{
continue;
}
// Crossing mode 2: building path over track
else if (
crossingMode == 2 && canBuildCrossing && tileElement->GetType() == TILE_ELEMENT_TYPE_TRACK
&& tileElement->GetBaseZ() == pos.baseZ && tileElement->AsTrack()->GetTrackType() == TrackElemType::Flat)
{
auto ride = get_ride(tileElement->AsTrack()->GetRideIndex());
if (ride != nullptr && ride->GetRideTypeDescriptor().HasFlag(RIDE_TYPE_FLAG_SUPPORTS_LEVEL_CROSSINGS))
{
continue;
}
}
if (tileElement != nullptr)
{
@ -1469,21 +1507,6 @@ std::unique_ptr<GameActions::ConstructClearResult> MapCanConstructWithClearAt(
res->Error = GameActions::Status::NoClearance;
}
return res;
loc_68BAE6:
if (clearFunc != nullptr)
{
if (!clearFunc(&tileElement, pos, flags, &res->Cost))
{
goto loc_68B9B7;
}
}
if (tileElement != nullptr)
{
res->Error = GameActions::Status::NoClearance;
res->ErrorMessage = STR_CANNOT_BUILD_PARTLY_ABOVE_AND_PARTLY_BELOW_WATER;
}
return res;
}
}
} while (!(tileElement++)->IsLastForTile());

View File

@ -13,7 +13,7 @@
#include <initializer_list>
#include <vector>
template<typename T, typename TExpected> static void AssertVector(std::vector<T> actual, TExpected expected)
template<typename T, typename TExpected> static void AssertVector(const std::vector<T>& actual, TExpected expected)
{
ASSERT_EQ(actual.size(), expected.size()) << "Expected vector of size " << expected.size() << ", but was " << actual.size();
size_t i = 0;
@ -24,7 +24,7 @@ template<typename T, typename TExpected> static void AssertVector(std::vector<T>
}
}
template<typename T> static void AssertVector(std::vector<T> actual, std::initializer_list<T> expected)
template<typename T> static void AssertVector(const std::vector<T>& actual, std::initializer_list<T> expected)
{
AssertVector<T, std::initializer_list<T>>(actual, expected);
}