mirror of https://github.com/OpenRCT2/OpenRCT2.git
Merge branch 'develop'
This commit is contained in:
commit
f219247b19
|
@ -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
|
@ -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 |
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -56,7 +56,7 @@ namespace OpenRCT2::Audio
|
|||
|
||||
~AudioMixerImpl() override
|
||||
{
|
||||
Close();
|
||||
AudioMixerImpl::Close();
|
||||
delete _nullSource;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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 });
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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));
|
||||
|
||||
|
|
|
@ -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 },
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue