OpenRCT2/src/openrct2/rct2/S6Importer.cpp

2874 lines
127 KiB
C++
Raw Normal View History

2016-05-07 14:58:36 +02:00
/*****************************************************************************
* Copyright (c) 2014-2024 OpenRCT2 developers
2016-05-07 14:58:36 +02:00
*
* For a complete list of all authors, please refer to contributors.md
* Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
2016-05-07 14:58:36 +02:00
*
* OpenRCT2 is licensed under the GNU General Public License version 3.
2016-05-07 14:58:36 +02:00
*****************************************************************************/
#include "../Context.h"
#include "../Diagnostic.h"
2021-04-05 19:01:43 +02:00
#include "../Editor.h"
2018-06-22 23:05:29 +02:00
#include "../Game.h"
#include "../GameState.h"
#include "../OpenRCT2.h"
#include "../ParkImporter.h"
#include "../config/Config.h"
#include "../core/Console.hpp"
#include "../core/FileStream.h"
2016-05-07 14:58:36 +02:00
#include "../core/IStream.hpp"
#include "../core/MemoryStream.h"
#include "../core/Numerics.hpp"
#include "../core/Path.hpp"
#include "../core/Random.hpp"
#include "../core/String.hpp"
2021-11-24 15:48:33 +01:00
#include "../entity/Balloon.h"
#include "../entity/Duck.h"
#include "../entity/EntityList.h"
2021-11-24 15:58:01 +01:00
#include "../entity/EntityRegistry.h"
2021-11-24 15:48:33 +01:00
#include "../entity/EntityTweener.h"
#include "../entity/Fountain.h"
2021-11-25 22:47:24 +01:00
#include "../entity/Guest.h"
2021-11-24 15:48:33 +01:00
#include "../entity/Litter.h"
#include "../entity/MoneyEffect.h"
#include "../entity/Particle.h"
2022-03-08 01:14:52 +01:00
#include "../entity/PatrolArea.h"
2021-11-25 22:47:24 +01:00
#include "../entity/Staff.h"
2018-01-06 00:45:53 +01:00
#include "../interface/Viewport.h"
2018-01-06 18:32:25 +01:00
#include "../localisation/Date.h"
#include "../localisation/Localisation.h"
#include "../management/Award.h"
2017-10-06 22:37:06 +02:00
#include "../management/Finance.h"
2017-10-11 21:38:26 +02:00
#include "../management/Marketing.h"
#include "../management/NewsItem.h"
#include "../management/Research.h"
#include "../network/network.h"
2023-01-26 19:44:42 +01:00
#include "../object/LargeSceneryEntry.h"
#include "../object/ObjectLimits.h"
#include "../object/ObjectList.h"
#include "../object/ObjectManager.h"
#include "../object/ObjectRepository.h"
#include "../object/WallSceneryEntry.h"
#include "../peep/RideUseSystem.h"
#include "../rct12/EntryList.h"
2020-11-24 15:40:27 +01:00
#include "../rct12/RCT12.h"
#include "../rct12/SawyerChunkReader.h"
#include "../rct2/RCT2.h"
2017-12-31 13:21:34 +01:00
#include "../ride/Ride.h"
2021-02-08 21:28:41 +01:00
#include "../ride/RideData.h"
2018-01-18 23:33:06 +01:00
#include "../ride/RideRatings.h"
#include "../ride/ShopItem.h"
#include "../ride/Station.h"
2019-09-19 22:56:54 +02:00
#include "../ride/Track.h"
#include "../ride/TrainManager.h"
#include "../ride/Vehicle.h"
2018-01-02 18:58:43 +01:00
#include "../scenario/Scenario.h"
#include "../scenario/ScenarioRepository.h"
2017-12-13 13:02:24 +01:00
#include "../util/SawyerCoding.h"
#include "../util/Util.h"
#include "../world/Climate.h"
2017-12-14 10:34:12 +01:00
#include "../world/Entrance.h"
2018-01-11 10:59:26 +01:00
#include "../world/MapAnimation.h"
2017-12-31 21:40:00 +01:00
#include "../world/Park.h"
#include "../world/Scenery.h"
2018-05-01 16:33:16 +02:00
#include "../world/Surface.h"
2021-11-21 19:25:27 +01:00
#include "../world/TilePointerIndex.hpp"
2016-05-07 14:58:36 +02:00
2018-06-22 23:05:29 +02:00
#include <algorithm>
using namespace OpenRCT2;
namespace RCT2
2016-05-07 14:58:36 +02:00
{
#define DECRYPT_MONEY(money) (static_cast<money32>(Numerics::rol32((money) ^ 0xF4EC9621, 13)))
2016-05-07 14:58:36 +02:00
/**
* Class to import RollerCoaster Tycoon 2 scenarios (*.SC6) and saved games (*.SV6).
*/
class S6Importer final : public IParkImporter
2016-05-07 23:47:29 +02:00
{
private:
IObjectRepository& _objectRepository;
2016-05-07 23:47:29 +02:00
u8string _s6Path;
S6Data _s6{};
uint8_t _gameVersion = 0;
bool _isSV7 = false;
bool _isScenario = false;
2021-12-13 14:47:19 +01:00
OpenRCT2::BitSet<Limits::MaxRidesInPark> _isFlatRide{};
ObjectEntryIndex _pathToSurfaceMap[16];
ObjectEntryIndex _pathToQueueSurfaceMap[16];
ObjectEntryIndex _pathToRailingMap[16];
RCT12::EntryList _terrainSurfaceEntries;
RCT12::EntryList _terrainEdgeEntries;
2016-05-07 14:58:36 +02:00
public:
S6Importer(IObjectRepository& objectRepository)
: _objectRepository(objectRepository)
2017-01-31 21:19:26 +01:00
{
}
ParkLoadResult Load(const u8string& path) override
{
2022-01-08 13:57:29 +01:00
const auto extension = Path::GetExtension(path);
if (String::IEquals(extension, ".sc6"))
{
return LoadScenario(path);
}
if (String::IEquals(extension, ".sv6"))
{
return LoadSavedGame(path);
}
throw std::runtime_error("Invalid RCT2 park extension.");
}
2016-05-07 14:58:36 +02:00
ParkLoadResult LoadSavedGame(const u8string& path, bool skipObjectCheck = false) override
{
auto fs = OpenRCT2::FileStream(path, OpenRCT2::FILE_MODE_OPEN);
auto result = LoadFromStream(&fs, false, skipObjectCheck);
_s6Path = path;
return result;
}
ParkLoadResult LoadScenario(const u8string& path, bool skipObjectCheck = false) override
{
auto fs = OpenRCT2::FileStream(path, OpenRCT2::FILE_MODE_OPEN);
auto result = LoadFromStream(&fs, true, skipObjectCheck);
_s6Path = path;
return result;
}
2016-05-07 14:58:36 +02:00
ParkLoadResult LoadFromStream(
OpenRCT2::IStream* stream, bool isScenario, [[maybe_unused]] bool skipObjectCheck = false,
const u8string& path = {}) override
{
auto chunkReader = SawyerChunkReader(stream);
2023-01-22 20:16:41 +01:00
chunkReader.ReadChunk(&_s6.Header, sizeof(_s6.Header));
2021-09-08 18:42:30 +02:00
2023-01-22 20:16:41 +01:00
LOG_VERBOSE("saved game classic_flag = 0x%02x", _s6.Header.ClassicFlag);
if (isScenario)
{
2023-01-22 20:16:41 +01:00
if (_s6.Header.Type != S6_TYPE_SCENARIO)
{
throw std::runtime_error("Park is not a scenario.");
}
2023-01-22 20:16:41 +01:00
chunkReader.ReadChunk(&_s6.Info, sizeof(_s6.Info));
}
else
{
2023-01-22 20:16:41 +01:00
if (_s6.Header.Type != S6_TYPE_SAVEDGAME)
{
throw std::runtime_error("Park is not a saved game.");
}
}
// Read packed objects
// TODO try to contain this more and not store objects until later
2023-01-22 20:16:41 +01:00
for (uint16_t i = 0; i < _s6.Header.NumPackedObjects; i++)
{
_objectRepository.ExportPackedObject(stream);
}
2016-05-07 14:58:36 +02:00
if (!path.empty())
{
auto extension = Path::GetExtension(path);
_isSV7 = String::IEquals(extension, ".sv7");
}
2016-05-07 14:58:36 +02:00
chunkReader.ReadChunk(&_s6.Objects, sizeof(_s6.Objects));
if (isScenario)
{
2023-01-22 20:16:41 +01:00
chunkReader.ReadChunk(&_s6.ElapsedMonths, 16);
chunkReader.ReadChunk(&_s6.TileElements, sizeof(_s6.TileElements));
ReadChunk6(chunkReader, 76);
2023-01-22 20:16:41 +01:00
chunkReader.ReadChunk(&_s6.GuestsInPark, 4);
chunkReader.ReadChunk(&_s6.LastGuestsInPark, 8);
chunkReader.ReadChunk(&_s6.ParkRating, 2);
chunkReader.ReadChunk(&_s6.ActiveResearchTypes, 1082);
chunkReader.ReadChunk(&_s6.CurrentExpenditure, 16);
chunkReader.ReadChunk(&_s6.ParkValue, 4);
chunkReader.ReadChunk(&_s6.CompletedCompanyValue, 483816);
}
else
{
2023-01-22 20:16:41 +01:00
chunkReader.ReadChunk(&_s6.ElapsedMonths, 16);
chunkReader.ReadChunk(&_s6.TileElements, sizeof(_s6.TileElements));
ReadChunk6(chunkReader, 488816);
}
2016-05-07 14:58:36 +02:00
_isScenario = isScenario;
_s6Path = path;
return ParkLoadResult(GetRequiredObjects());
}
void ReadChunk6(SawyerChunkReader& chunkReader, uint32_t sizeWithoutEntities)
{
uint32_t entitiesSize = GetMaxEntities() * sizeof(Entity);
2022-08-23 23:00:31 +02:00
size_t bufferSize = sizeWithoutEntities + entitiesSize;
std::vector<uint8_t> buffer(bufferSize);
chunkReader.ReadChunk(buffer.data(), buffer.size());
auto stream = OpenRCT2::MemoryStream(buffer.data(), buffer.size());
2023-01-22 20:16:41 +01:00
uint32_t preEntitiesSize = sizeof(_s6.NextFreeTileElementPointerIndex);
uint32_t postEntitiesSize = sizeWithoutEntities - preEntitiesSize;
2023-01-22 20:16:41 +01:00
stream.Read(&_s6.NextFreeTileElementPointerIndex, preEntitiesSize);
stream.Read(&_s6.Entities, entitiesSize);
stream.Read(&_s6.EntityListsHead, postEntitiesSize);
}
bool GetDetails(ScenarioIndexEntry* dst) override
{
*dst = {};
return false;
}
void Import(GameState_t& gameState) override
{
2024-03-26 15:08:17 +01:00
Initialise(gameState);
2016-05-07 14:58:36 +02:00
gameState.EditorStep = _s6.Info.EditorStep;
gameState.ScenarioCategory = static_cast<SCENARIO_CATEGORY>(_s6.Info.Category);
// Some scenarios have their scenario details in UTF-8, due to earlier bugs in OpenRCT2.
auto loadMaybeUTF8 = [](std::string_view str) -> std::string {
return !IsLikelyUTF8(str) ? RCT2StringToUTF8(str, RCT2LanguageId::EnglishUK) : std::string(str);
};
2017-01-23 14:00:46 +01:00
2023-01-22 20:16:41 +01:00
if (_s6.Header.Type == S6_TYPE_SCENARIO)
{
gameState.ScenarioName = loadMaybeUTF8(_s6.Info.Name);
gameState.ScenarioDetails = loadMaybeUTF8(_s6.Info.Details);
}
else
{
// Saved games do not have an info chunk
gameState.ScenarioName = loadMaybeUTF8(_s6.ScenarioName);
gameState.ScenarioDetails = loadMaybeUTF8(_s6.ScenarioDescription);
}
2024-03-26 17:32:36 +01:00
gameState.Date = OpenRCT2::Date{ _s6.ElapsedMonths, _s6.CurrentDay };
gameState.CurrentTicks = _s6.GameTicks1;
2023-01-22 20:16:41 +01:00
ScenarioRandSeed(_s6.ScenarioSrand0, _s6.ScenarioSrand1);
2018-06-22 23:05:29 +02:00
DetermineFlatRideStatus();
ImportTileElements();
ImportEntities();
gameState.InitialCash = ToMoney64(_s6.InitialCash);
gameState.BankLoan = ToMoney64(_s6.CurrentLoan);
2022-04-09 13:36:31 +02:00
gameState.Park.Flags = _s6.ParkFlags & ~PARK_FLAGS_NO_MONEY_SCENARIO;
2022-04-09 13:36:31 +02:00
// RCT2 used a different flag for `no money` when the park is a scenario
2023-01-22 20:16:41 +01:00
if (_s6.Header.Type == S6_TYPE_SCENARIO)
{
2023-01-22 20:16:41 +01:00
if (_s6.ParkFlags & PARK_FLAGS_NO_MONEY_SCENARIO)
gameState.Park.Flags |= PARK_FLAGS_NO_MONEY;
else
gameState.Park.Flags &= ~PARK_FLAGS_NO_MONEY;
}
2022-04-09 13:36:31 +02:00
gameState.Park.EntranceFee = _s6.ParkEntranceFee;
2023-01-22 20:16:41 +01:00
// rct1_park_entranceX
// rct1_park_entrance_y
2023-01-21 16:39:35 +01:00
// Pad013573EE
// rct1_park_entrance_z
ImportPeepSpawns();
gameState.GuestChangeModifier = _s6.GuestCountChangeModifier;
2024-01-29 21:33:39 +01:00
gameState.ResearchFundingLevel = _s6.CurrentResearchLevel;
2023-01-21 16:39:35 +01:00
// Pad01357400
2023-01-22 20:16:41 +01:00
// _s6.ResearchedTrackTypesA
// _s6.ResearchedTrackTypesB
gameState.NumGuestsInPark = _s6.GuestsInPark;
gameState.NumGuestsHeadingForPark = _s6.GuestsHeadingForPark;
for (size_t i = 0; i < Limits::ExpenditureTableMonthCount; i++)
{
for (size_t j = 0; j < Limits::ExpenditureTypeCount; j++)
{
2024-03-04 15:24:29 +01:00
gameState.ExpenditureTable[i][j] = ToMoney64(_s6.ExpenditureTable[i][j]);
}
}
gameState.NumGuestsInParkLastWeek = _s6.LastGuestsInPark;
2023-01-21 16:39:35 +01:00
// Pad01357BCA
gameState.StaffHandymanColour = _s6.HandymanColour;
gameState.StaffMechanicColour = _s6.MechanicColour;
gameState.StaffSecurityColour = _s6.SecurityColour;
gameState.Park.Rating = _s6.ParkRating;
Park::ResetHistories(gameState);
std::copy(std::begin(_s6.ParkRatingHistory), std::end(_s6.ParkRatingHistory), gameState.Park.RatingHistory);
2023-01-22 20:16:41 +01:00
for (size_t i = 0; i < std::size(_s6.GuestsInParkHistory); i++)
{
2023-01-22 20:16:41 +01:00
if (_s6.GuestsInParkHistory[i] != RCT12ParkHistoryUndefined)
{
gameState.GuestsInParkHistory[i] = _s6.GuestsInParkHistory[i] * RCT12GuestsInParkHistoryFactor;
}
}
2024-01-29 21:33:39 +01:00
gameState.ResearchPriorities = _s6.ActiveResearchTypes;
gameState.ResearchProgressStage = _s6.ResearchProgressStage;
2023-01-22 20:16:41 +01:00
if (_s6.LastResearchedItemSubject != RCT12_RESEARCHED_ITEMS_SEPARATOR)
2024-01-29 21:33:39 +01:00
gameState.ResearchLastItem = RCT12ResearchItem{ _s6.LastResearchedItemSubject,
EnumValue(ResearchCategory::Transport) }
.ToResearchItem();
else
2024-01-29 21:33:39 +01:00
gameState.ResearchLastItem = std::nullopt;
2023-01-21 16:39:35 +01:00
// Pad01357CF8
2023-01-22 20:16:41 +01:00
if (_s6.NextResearchItem != RCT12_RESEARCHED_ITEMS_SEPARATOR)
2024-01-29 21:33:39 +01:00
gameState.ResearchNextItem = RCT12ResearchItem{ _s6.NextResearchItem, _s6.NextResearchCategory }
.ToResearchItem();
else
2024-01-29 21:33:39 +01:00
gameState.ResearchNextItem = std::nullopt;
2024-01-29 21:33:39 +01:00
gameState.ResearchProgress = _s6.ResearchProgress;
gameState.ResearchExpectedDay = _s6.NextResearchExpectedDay;
gameState.ResearchExpectedMonth = _s6.NextResearchExpectedMonth;
2024-01-22 23:28:16 +01:00
gameState.GuestInitialHappiness = _s6.GuestInitialHappiness;
gameState.Park.Size = _s6.ParkSize;
gameState.GuestGenerationProbability = _s6.GuestGenerationProbability;
gameState.TotalRideValueForMoney = _s6.TotalRideValueForMoney;
2024-02-13 21:36:35 +01:00
gameState.MaxBankLoan = ToMoney64(_s6.MaximumLoan);
2024-01-22 23:28:16 +01:00
gameState.GuestInitialCash = ToMoney64(_s6.GuestInitialCash);
gameState.GuestInitialHunger = _s6.GuestInitialHunger;
gameState.GuestInitialThirst = _s6.GuestInitialThirst;
gameState.ScenarioObjective.Type = _s6.ObjectiveType;
gameState.ScenarioObjective.Year = _s6.ObjectiveYear;
2023-01-21 16:39:35 +01:00
// Pad013580FA
gameState.ScenarioObjective.Currency = _s6.ObjectiveCurrency;
// In RCT2, the ride string IDs start at index STR_0002 and are directly mappable.
// This is not always the case in OpenRCT2, so we use the actual ride ID.
if (gameState.ScenarioObjective.Type == OBJECTIVE_BUILD_THE_BEST)
gameState.ScenarioObjective.RideId = _s6.ObjectiveGuests - RCT2_RIDE_STRING_START;
else
gameState.ScenarioObjective.NumGuests = _s6.ObjectiveGuests;
ImportMarketingCampaigns();
gameState.CurrentExpenditure = ToMoney64(_s6.CurrentExpenditure);
gameState.CurrentProfit = ToMoney64(_s6.CurrentProfit);
2024-01-24 15:03:46 +01:00
gameState.WeeklyProfitAverageDividend = ToMoney64(_s6.WeeklyProfitAverageDividend);
gameState.WeeklyProfitAverageDivisor = _s6.WeeklyProfitAverageDivisor;
2023-01-21 16:39:35 +01:00
// Pad0135833A
gameState.Park.Value = ToMoney64(_s6.ParkValue);
for (size_t i = 0; i < Limits::FinanceGraphSize; i++)
{
2024-03-02 20:41:16 +01:00
gameState.CashHistory[i] = ToMoney64(_s6.BalanceHistory[i]);
2024-01-24 15:03:46 +01:00
gameState.WeeklyProfitHistory[i] = ToMoney64(_s6.WeeklyProfitHistory[i]);
gameState.Park.ValueHistory[i] = ToMoney64(_s6.ParkValueHistory[i]);
}
gameState.ScenarioCompletedCompanyValue = RCT12CompletedCompanyValueToOpenRCT2(_s6.CompletedCompanyValue);
gameState.TotalAdmissions = _s6.TotalAdmissions;
gameState.TotalIncomeFromAdmissions = ToMoney64(_s6.IncomeFromAdmissions);
2024-02-27 16:31:38 +01:00
gameState.CompanyValue = ToMoney64(_s6.CompanyValue);
std::memcpy(gameState.PeepWarningThrottle, _s6.PeepWarningThrottle, sizeof(_s6.PeepWarningThrottle));
// Awards
2024-03-14 22:16:33 +01:00
auto& currentAwards = gameState.CurrentAwards;
2023-01-22 20:16:41 +01:00
for (auto& src : _s6.Awards)
{
2023-01-22 20:16:41 +01:00
if (src.Time != 0)
{
2024-03-14 22:16:33 +01:00
currentAwards.push_back(Award{ src.Time, static_cast<AwardType>(src.Type) });
}
}
2024-03-07 19:44:21 +01:00
gameState.LandPrice = ToMoney64(_s6.LandPrice);
gameState.ConstructionRightsPrice = ToMoney64(_s6.ConstructionRightsPrice);
// unk_01358774
2023-01-21 16:39:35 +01:00
// Pad01358776
2023-01-22 20:16:41 +01:00
// _s6.CdKey
_gameVersion = _s6.GameVersionNumber;
gameState.ScenarioCompanyValueRecord = _s6.CompletedCompanyValueRecord;
2023-01-22 20:16:41 +01:00
// _s6.LoanHash;
2023-01-21 16:39:35 +01:00
// Pad013587CA
gameState.HistoricalProfit = ToMoney64(_s6.HistoricalProfit);
2023-01-21 16:39:35 +01:00
// Pad013587D4
gameState.ScenarioCompletedBy = std::string_view(_s6.ScenarioCompletedName, sizeof(_s6.ScenarioCompletedName));
gameState.Cash = ToMoney64(DECRYPT_MONEY(_s6.Cash));
2023-01-21 16:39:35 +01:00
// Pad013587FC
gameState.Park.RatingCasualtyPenalty = _s6.ParkRatingCasualtyPenalty;
2024-02-12 22:32:08 +01:00
gameState.MapSize = { _s6.MapSize, _s6.MapSize };
gameState.SamePriceThroughoutPark = _s6.SamePriceThroughout
| (static_cast<uint64_t>(_s6.SamePriceThroughoutExtended) << 32);
gameState.SuggestedGuestMaximum = _s6.SuggestedMaxGuests;
gameState.ScenarioParkRatingWarningDays = _s6.ParkRatingWarningDays;
2024-03-09 11:27:05 +01:00
gameState.LastEntranceStyle = _s6.LastEntranceStyle;
// rct1_water_colour
2023-01-21 16:39:35 +01:00
// Pad01358842
2024-01-29 21:33:39 +01:00
ImportResearchList(gameState);
gameState.BankLoanInterestRate = _s6.CurrentInterestRate;
2023-01-21 16:39:35 +01:00
// Pad0135934B
// Preserve compatibility with vanilla RCT2's save format.
gameState.Park.Entrances.clear();
for (uint8_t i = 0; i < Limits::MaxParkEntrances; i++)
{
2023-01-22 20:16:41 +01:00
if (_s6.ParkEntranceX[i] != LOCATION_NULL)
{
CoordsXYZD entrance;
2023-01-22 20:16:41 +01:00
entrance.x = _s6.ParkEntranceX[i];
entrance.y = _s6.ParkEntranceY[i];
entrance.z = _s6.ParkEntranceZ[i];
entrance.direction = _s6.ParkEntranceDirection[i];
gameState.Park.Entrances.push_back(entrance);
}
}
2023-01-22 20:16:41 +01:00
if (_s6.Header.Type == S6_TYPE_SCENARIO)
{
2023-01-22 20:16:41 +01:00
// _s6.ScenarioFilename is wrong for some RCT2 expansion scenarios, so we use the real filename
2022-01-08 13:57:29 +01:00
gScenarioFileName = Path::GetFileName(_s6Path);
}
else
{
// For savegames the filename can be arbitrary, so we have no choice but to rely on the name provided
2023-01-22 20:16:41 +01:00
gScenarioFileName = std::string(String::ToStringView(_s6.ScenarioFilename, std::size(_s6.ScenarioFilename)));
}
gCurrentRealTimeTicks = 0;
ImportRides();
gameState.SavedView = ScreenCoordsXY{ _s6.SavedViewX, _s6.SavedViewY };
gameState.SavedViewZoom = ZoomLevel{ static_cast<int8_t>(_s6.SavedViewZoom) };
gameState.SavedViewRotation = _s6.SavedViewRotation;
ImportRideRatingsCalcData();
ImportRideMeasurements();
2024-01-25 10:34:47 +01:00
gameState.NextGuestNumber = _s6.NextGuestIndex;
gameState.GrassSceneryTileLoopPosition = _s6.GrassAndSceneryTilepos;
// unk_13CA73E
2023-01-21 16:39:35 +01:00
// Pad13CA73F
// unk_13CA740
2024-01-21 22:05:22 +01:00
gameState.Climate = ClimateType{ _s6.Climate };
2023-01-21 16:39:35 +01:00
// Pad13CA741;
2023-01-21 16:41:03 +01:00
// Byte13CA742
2023-01-21 16:39:35 +01:00
// Pad013CA747
gameState.ClimateUpdateTimer = _s6.ClimateUpdateTimer;
2024-01-24 11:18:54 +01:00
gameState.ClimateCurrent.Weather = WeatherType{ _s6.CurrentWeather };
gameState.ClimateNext.Weather = WeatherType{ _s6.NextWeather };
2024-01-24 11:18:54 +01:00
gameState.ClimateCurrent.Temperature = _s6.Temperature;
gameState.ClimateNext.Temperature = _s6.NextTemperature;
2024-01-24 11:18:54 +01:00
gameState.ClimateCurrent.WeatherEffect = WeatherEffectType{ _s6.CurrentWeatherEffect };
gameState.ClimateNext.WeatherEffect = WeatherEffectType{ _s6.NextWeatherEffect };
2024-01-24 11:18:54 +01:00
gameState.ClimateCurrent.WeatherGloom = _s6.CurrentWeatherGloom;
gameState.ClimateNext.WeatherGloom = _s6.NextWeatherGloom;
2024-01-24 11:18:54 +01:00
gameState.ClimateCurrent.Level = static_cast<WeatherLevel>(_s6.CurrentWeatherLevel);
gameState.ClimateNext.Level = static_cast<WeatherLevel>(_s6.NextWeatherLevel);
// News items
News::InitQueue();
for (size_t i = 0; i < Limits::MaxNewsItems; i++)
{
2023-01-22 20:16:41 +01:00
const RCT12NewsItem* src = &_s6.NewsItems[i];
2024-02-14 11:54:15 +01:00
News::Item* dst = &gameState.NewsItems[i];
if (src->Type < News::ItemTypeCount)
{
dst->Type = static_cast<News::ItemType>(src->Type);
dst->Flags = src->Flags;
dst->Assoc = src->Assoc;
dst->Ticks = src->Ticks;
dst->MonthYear = src->MonthYear;
dst->Day = src->Day;
dst->Text = ConvertFormattedStringToOpenRCT2(std::string_view(src->Text, sizeof(src->Text)));
}
else
{
// In case where news item type is broken, consider all remaining news items invalid.
LOG_ERROR("Invalid news type 0x%x for news item %d, ignoring remaining news items", src->Type, i);
// Still need to set the correct type to properly terminate the queue
dst->Type = News::ItemType::Null;
break;
}
}
2023-01-21 16:39:35 +01:00
// Pad13CE730
// rct1_scenario_flags
gameState.WidePathTileLoopPosition = { _s6.WidePathTileLoopX, _s6.WidePathTileLoopY };
2023-01-21 16:39:35 +01:00
// Pad13CE778
2017-01-14 19:47:18 +01:00
// Fix and set dynamic variables
MapStripGhostFlagFromElements();
ConvertScenarioStringsToUTF8(gameState);
DetermineRideEntranceAndExitLocations();
2024-03-26 19:01:50 +01:00
gameState.Park.Name = GetUserString(_s6.ParkName);
FixLandOwnership();
FixWater();
FixAyersRockScenario();
ResearchDetermineFirstOfType();
2022-03-08 01:14:52 +01:00
UpdateConsolidatedPatrolAreas();
CheatsReset();
ClearRestrictedScenery();
}
void AddDefaultEntries()
{
// Add default surfaces
_terrainSurfaceEntries.AddRange(DefaultTerrainSurfaces);
// Add default edges
_terrainEdgeEntries.AddRange(DefaultTerrainEdges);
}
void ConvertScenarioStringsToUTF8(GameState_t& gameState)
2021-11-28 22:53:40 +01:00
{
// Scenario details
gameState.ScenarioCompletedBy = RCT2StringToUTF8(gameState.ScenarioCompletedBy, RCT2LanguageId::EnglishUK);
gameState.ScenarioName = RCT2StringToUTF8(gameState.ScenarioName, RCT2LanguageId::EnglishUK);
gameState.ScenarioDetails = RCT2StringToUTF8(gameState.ScenarioDetails, RCT2LanguageId::EnglishUK);
2021-11-28 22:53:40 +01:00
}
void FixLandOwnership() const
{
2023-01-22 20:16:41 +01:00
// Checking _s6.ScenarioFilename is generally more reliable as it survives renaming.
// However, some WW/TT scenarios have this incorrectly set to "Six Flags Magic Mountain.SC6",
// so for those cases (as well as for SFMM proper, well have to check the filename.
2023-01-22 20:16:41 +01:00
if (String::Equals(_s6.ScenarioFilename, "Europe - European Cultural Festival.SC6"))
{
// This scenario breaks pathfinding. Create passages between the worlds. (List is grouped by neighbouring
// tiles.)
// clang-format off
2021-11-24 18:58:07 +01:00
FixLandOwnershipTilesWithOwnership(
{
{ 67, 94 }, { 68, 94 }, { 69, 94 },
{ 58, 24 }, { 58, 25 }, { 58, 26 }, { 58, 27 }, { 58, 28 }, { 58, 29 }, { 58, 30 }, { 58, 31 }, { 58, 32 },
{ 26, 44 }, { 26, 45 },
{ 32, 79 }, { 32, 80 }, { 32, 81 },
},
OWNERSHIP_OWNED);
// clang-format on
}
Fix #17774: gaps and errors in park boundaries and construction rights for RCT1 and RCT2 scenarios (#19657) * Update S6Importer.cpp * clang format error. Added changelog entry. * Update S6Importer.cpp * Added fixes for RCT1 scenarios The issues in Katie's Dreamland, Utopia Park, Urban Park, Pleasure Island, and Fort Anachronism listed in issue #17774 have been now dealt with. * Added land for Cradle's underwater path. * Update changelog.txt * Updated changelog. * specify text for path fix in Cradle * Update S6Importer.cpp * More missing tiles in Coastal Reclaim & Salvage * Update S6Importer.cpp * Update S6Importer.cpp * missed tile in stone age * Classic compatibility Added edit compatibility for classic scenarios on rct2 maps. * Update changelog.txt * Update S6Importer.cpp * Update S6Importer.cpp * Update S6Importer.cpp * Fun At The Beach Fixed errant tiles in Fun at the Beach. * Update S6Importer.cpp * Update S6Importer.cpp * Extreme Heights Fix missing tiles along edge of Extreme Heights park boundary; should run to 1 tile from the edge of the map almost all the way around. * Final Set of Changes Did a quick run-through of all the maps looking for any possible missed spots. I did find a series of spots, some clearly meant to be owned, and others that I'm a bit less than sure about. For now, I've commented out the spots that I don't feel are strictly necessary to have included, while the remaining ones I feel are necessary. * Update S4Importer.cpp * add optional fixes un-commented the extra changes; they are now included. * Update changelog.txt * fix clang format error * Update changelog.txt * Update S6Importer.cpp OOB underground path * Update S6Importer.cpp * Update S6Importer.cpp * above runaway plumber gaps * Update changelog.txt
2023-11-17 12:23:05 +01:00
else if (String::Equals(gScenarioFileName, "trinity islands.sea"))
{
// clang-format off
FixLandOwnershipTilesWithOwnership(
{
{ 80, 60 },
},
OWNERSHIP_CONSTRUCTION_RIGHTS_OWNED);
// clang-format on
}
else if (String::Equals(gScenarioFileName, "katie's dreamland.sea"))
{
// clang-format off
FixLandOwnershipTilesWithOwnership(
{
{ 115, 63 }, { 105, 66 }, { 109, 66 }, /*{ 118, 67 }*/
},
OWNERSHIP_CONSTRUCTION_RIGHTS_OWNED);
FixLandOwnershipTilesWithOwnership(
{
{ 45, 69 }, { 59, 74 }
},
OWNERSHIP_OWNED);
// clang-format on
}
else if (String::Equals(gScenarioFileName, "white water park.sea"))
{
// clang-format off
FixLandOwnershipTilesWithOwnership(
{
{ 42, 85 }, { 89, 42 }
},
OWNERSHIP_CONSTRUCTION_RIGHTS_OWNED);
// clang-format on
}
else if (String::Equals(gScenarioFileName, "mel's world.sea"))
{
// clang-format off
FixLandOwnershipTilesWithOwnership(
{
{ 93, 76 }, { 93, 77 }
},
OWNERSHIP_OWNED);
// clang-format on
}
else if (String::Equals(gScenarioFileName, "three monkeys park.sea"))
{
// clang-format off
FixLandOwnershipTilesWithOwnership(
{
{ 46, 22 }
},
OWNERSHIP_OWNED);
FixLandOwnershipTilesWithOwnership(
{
{ 89, 92 }
},
OWNERSHIP_UNOWNED);
// clang-format on
}
else if (String::Equals(gScenarioFileName, "coaster canyon.sea"))
{
// clang-format off
FixLandOwnershipTilesWithOwnership(
{
{ 21, 55 }
},
OWNERSHIP_OWNED);
// clang-format on
}
else if (String::Equals(gScenarioFileName, "rotting heights.sea"))
{
// clang-format off
FixLandOwnershipTilesWithOwnership(
{
{ 35, 20 }
},
OWNERSHIP_OWNED);
// clang-format on
}
else if (String::Equals(gScenarioFileName, "grand glacier.sea"))
{
// clang-format off
FixLandOwnershipTilesWithOwnership(
{
{ 99, 58 }
},
OWNERSHIP_OWNED);
// clang-format on
}
else if (String::Equals(gScenarioFileName, "woodworm park.sea"))
{
// clang-format off
FixLandOwnershipTilesWithOwnership(
{
{ 62, 105 }, { 101, 55 }
},
OWNERSHIP_OWNED);
// clang-format on
}
else if (String::Equals(gScenarioFileName, "pleasure island.sea"))
{
// clang-format off
FixLandOwnershipTilesWithOwnership(
{
{ 37, 66 },
},
OWNERSHIP_CONSTRUCTION_RIGHTS_OWNED);
// clang-format on
}
else if (String::Equals(_s6.ScenarioFilename, "Crazy Castle.SC6"))
{
// clang-format off
FixLandOwnershipTilesWithOwnership(
{
{ 2, 4 }, { 2, 62 }, { 2, 63 }, { 2, 83 }, { 2, 84 }, { 9, 4 }
},
OWNERSHIP_AVAILABLE);
// clang-format on
}
else if (String::Equals(_s6.ScenarioFilename, "Extreme Heights.SC6"))
{
// clang-format off
FixLandOwnershipTilesWithOwnership(
{
{ 105, 147 }, { 106, 147 }, { 107, 147 },
},
OWNERSHIP_OWNED);
// clang-format on
}
else if (String::Equals(_s6.ScenarioFilename, "Ghost Town.SC6"))
{
// clang-format off
FixLandOwnershipTilesWithOwnership(
{
{ 43, 79 }, { 42, 80 }, { 43, 80 },
},
OWNERSHIP_OWNED);
// clang-format on
}
else if (String::Equals(_s6.ScenarioFilename, "Six Flags Great Adventure.SC6"))
{
// clang-format off
FixLandOwnershipTilesWithOwnership(
{
{ 241, 59 }, { 242, 59 },
},
OWNERSHIP_UNOWNED);
FixLandOwnershipTilesWithOwnership(
{
{ 145, 31 }
},
OWNERSHIP_OWNED);
// clang-format on
}
2023-01-22 20:16:41 +01:00
else if (String::Equals(_s6.ScenarioFilename, "Six Flags Holland.SC6"))
{
// clang-format off
FixLandOwnershipTilesWithOwnership(
{
{ 112, 33 }, { 112, 34 },
{ 113, 117 }, { 114, 117 }, { 115, 117 }, { 116, 117 }, { 117, 117 }, { 114, 118 }, { 115, 118 }, { 116, 118 }, { 117, 118 },
},
OWNERSHIP_AVAILABLE, true);
// clang-format on
}
Fix #17774: gaps and errors in park boundaries and construction rights for RCT1 and RCT2 scenarios (#19657) * Update S6Importer.cpp * clang format error. Added changelog entry. * Update S6Importer.cpp * Added fixes for RCT1 scenarios The issues in Katie's Dreamland, Utopia Park, Urban Park, Pleasure Island, and Fort Anachronism listed in issue #17774 have been now dealt with. * Added land for Cradle's underwater path. * Update changelog.txt * Updated changelog. * specify text for path fix in Cradle * Update S6Importer.cpp * More missing tiles in Coastal Reclaim & Salvage * Update S6Importer.cpp * Update S6Importer.cpp * missed tile in stone age * Classic compatibility Added edit compatibility for classic scenarios on rct2 maps. * Update changelog.txt * Update S6Importer.cpp * Update S6Importer.cpp * Update S6Importer.cpp * Fun At The Beach Fixed errant tiles in Fun at the Beach. * Update S6Importer.cpp * Update S6Importer.cpp * Extreme Heights Fix missing tiles along edge of Extreme Heights park boundary; should run to 1 tile from the edge of the map almost all the way around. * Final Set of Changes Did a quick run-through of all the maps looking for any possible missed spots. I did find a series of spots, some clearly meant to be owned, and others that I'm a bit less than sure about. For now, I've commented out the spots that I don't feel are strictly necessary to have included, while the remaining ones I feel are necessary. * Update S4Importer.cpp * add optional fixes un-commented the extra changes; they are now included. * Update changelog.txt * fix clang format error * Update changelog.txt * Update S6Importer.cpp OOB underground path * Update S6Importer.cpp * Update S6Importer.cpp * above runaway plumber gaps * Update changelog.txt
2023-11-17 12:23:05 +01:00
else if (
String::IEquals(gScenarioFileName, "Six Flags Magic Mountain.SC6")
|| String::IEquals(gScenarioFileName, "six flags magic mountain.sea"))
{
// clang-format off
FixLandOwnershipTilesWithOwnership(
{
{ 104, 190 }, { 105, 190 }, { 108, 197 },
{ 75, 167 },
Fix #17774: gaps and errors in park boundaries and construction rights for RCT1 and RCT2 scenarios (#19657) * Update S6Importer.cpp * clang format error. Added changelog entry. * Update S6Importer.cpp * Added fixes for RCT1 scenarios The issues in Katie's Dreamland, Utopia Park, Urban Park, Pleasure Island, and Fort Anachronism listed in issue #17774 have been now dealt with. * Added land for Cradle's underwater path. * Update changelog.txt * Updated changelog. * specify text for path fix in Cradle * Update S6Importer.cpp * More missing tiles in Coastal Reclaim & Salvage * Update S6Importer.cpp * Update S6Importer.cpp * missed tile in stone age * Classic compatibility Added edit compatibility for classic scenarios on rct2 maps. * Update changelog.txt * Update S6Importer.cpp * Update S6Importer.cpp * Update S6Importer.cpp * Fun At The Beach Fixed errant tiles in Fun at the Beach. * Update S6Importer.cpp * Update S6Importer.cpp * Extreme Heights Fix missing tiles along edge of Extreme Heights park boundary; should run to 1 tile from the edge of the map almost all the way around. * Final Set of Changes Did a quick run-through of all the maps looking for any possible missed spots. I did find a series of spots, some clearly meant to be owned, and others that I'm a bit less than sure about. For now, I've commented out the spots that I don't feel are strictly necessary to have included, while the remaining ones I feel are necessary. * Update S4Importer.cpp * add optional fixes un-commented the extra changes; they are now included. * Update changelog.txt * fix clang format error * Update changelog.txt * Update S6Importer.cpp OOB underground path * Update S6Importer.cpp * Update S6Importer.cpp * above runaway plumber gaps * Update changelog.txt
2023-11-17 12:23:05 +01:00
{ 61, 92 }, { 61, 93 }, { 61, 94 }, { 61, 95 }, { 62, 90 }, { 62, 91 }, { 62, 92 }, { 62, 93 }, { 62, 94 },
{ 92, 57 }, { 93, 57 },
{ 89, 40 }, { 89, 41 }, { 89, 42 }, { 88, 42 },
Fix #17774: gaps and errors in park boundaries and construction rights for RCT1 and RCT2 scenarios (#19657) * Update S6Importer.cpp * clang format error. Added changelog entry. * Update S6Importer.cpp * Added fixes for RCT1 scenarios The issues in Katie's Dreamland, Utopia Park, Urban Park, Pleasure Island, and Fort Anachronism listed in issue #17774 have been now dealt with. * Added land for Cradle's underwater path. * Update changelog.txt * Updated changelog. * specify text for path fix in Cradle * Update S6Importer.cpp * More missing tiles in Coastal Reclaim & Salvage * Update S6Importer.cpp * Update S6Importer.cpp * missed tile in stone age * Classic compatibility Added edit compatibility for classic scenarios on rct2 maps. * Update changelog.txt * Update S6Importer.cpp * Update S6Importer.cpp * Update S6Importer.cpp * Fun At The Beach Fixed errant tiles in Fun at the Beach. * Update S6Importer.cpp * Update S6Importer.cpp * Extreme Heights Fix missing tiles along edge of Extreme Heights park boundary; should run to 1 tile from the edge of the map almost all the way around. * Final Set of Changes Did a quick run-through of all the maps looking for any possible missed spots. I did find a series of spots, some clearly meant to be owned, and others that I'm a bit less than sure about. For now, I've commented out the spots that I don't feel are strictly necessary to have included, while the remaining ones I feel are necessary. * Update S4Importer.cpp * add optional fixes un-commented the extra changes; they are now included. * Update changelog.txt * fix clang format error * Update changelog.txt * Update S6Importer.cpp OOB underground path * Update S6Importer.cpp * Update S6Importer.cpp * above runaway plumber gaps * Update changelog.txt
2023-11-17 12:23:05 +01:00
{ 168, 20 }, { 169, 20 },
{ 46, 51 }, { 58, 159 }, { 71, 201 }, { 126, 15 }, { 190, 6 }
},
OWNERSHIP_AVAILABLE, true);
// clang-format on
}
else if (
String::IEquals(gScenarioFileName, "Build your own Six Flags Magic Mountain.SC6")
|| String::IEquals(gScenarioFileName, "build your own six flags magic mountain.sea"))
{
// clang-format off
FixLandOwnershipTilesWithOwnership(
{
{ 104, 190 }, { 105, 190 }, { 108, 197 },
{ 75, 167 },
Fix #17774: gaps and errors in park boundaries and construction rights for RCT1 and RCT2 scenarios (#19657) * Update S6Importer.cpp * clang format error. Added changelog entry. * Update S6Importer.cpp * Added fixes for RCT1 scenarios The issues in Katie's Dreamland, Utopia Park, Urban Park, Pleasure Island, and Fort Anachronism listed in issue #17774 have been now dealt with. * Added land for Cradle's underwater path. * Update changelog.txt * Updated changelog. * specify text for path fix in Cradle * Update S6Importer.cpp * More missing tiles in Coastal Reclaim & Salvage * Update S6Importer.cpp * Update S6Importer.cpp * missed tile in stone age * Classic compatibility Added edit compatibility for classic scenarios on rct2 maps. * Update changelog.txt * Update S6Importer.cpp * Update S6Importer.cpp * Update S6Importer.cpp * Fun At The Beach Fixed errant tiles in Fun at the Beach. * Update S6Importer.cpp * Update S6Importer.cpp * Extreme Heights Fix missing tiles along edge of Extreme Heights park boundary; should run to 1 tile from the edge of the map almost all the way around. * Final Set of Changes Did a quick run-through of all the maps looking for any possible missed spots. I did find a series of spots, some clearly meant to be owned, and others that I'm a bit less than sure about. For now, I've commented out the spots that I don't feel are strictly necessary to have included, while the remaining ones I feel are necessary. * Update S4Importer.cpp * add optional fixes un-commented the extra changes; they are now included. * Update changelog.txt * fix clang format error * Update changelog.txt * Update S6Importer.cpp OOB underground path * Update S6Importer.cpp * Update S6Importer.cpp * above runaway plumber gaps * Update changelog.txt
2023-11-17 12:23:05 +01:00
{ 61, 92 }, { 61, 93 }, { 61, 94 }, { 61, 95 }, { 62, 90 }, { 62, 91 }, { 62, 92 }, { 62, 93 }, { 62, 94 },
{ 92, 57 }, { 93, 57 },
{ 89, 40 }, { 89, 41 }, { 89, 42 }, { 88, 42 },
Fix #17774: gaps and errors in park boundaries and construction rights for RCT1 and RCT2 scenarios (#19657) * Update S6Importer.cpp * clang format error. Added changelog entry. * Update S6Importer.cpp * Added fixes for RCT1 scenarios The issues in Katie's Dreamland, Utopia Park, Urban Park, Pleasure Island, and Fort Anachronism listed in issue #17774 have been now dealt with. * Added land for Cradle's underwater path. * Update changelog.txt * Updated changelog. * specify text for path fix in Cradle * Update S6Importer.cpp * More missing tiles in Coastal Reclaim & Salvage * Update S6Importer.cpp * Update S6Importer.cpp * missed tile in stone age * Classic compatibility Added edit compatibility for classic scenarios on rct2 maps. * Update changelog.txt * Update S6Importer.cpp * Update S6Importer.cpp * Update S6Importer.cpp * Fun At The Beach Fixed errant tiles in Fun at the Beach. * Update S6Importer.cpp * Update S6Importer.cpp * Extreme Heights Fix missing tiles along edge of Extreme Heights park boundary; should run to 1 tile from the edge of the map almost all the way around. * Final Set of Changes Did a quick run-through of all the maps looking for any possible missed spots. I did find a series of spots, some clearly meant to be owned, and others that I'm a bit less than sure about. For now, I've commented out the spots that I don't feel are strictly necessary to have included, while the remaining ones I feel are necessary. * Update S4Importer.cpp * add optional fixes un-commented the extra changes; they are now included. * Update changelog.txt * fix clang format error * Update changelog.txt * Update S6Importer.cpp OOB underground path * Update S6Importer.cpp * Update S6Importer.cpp * above runaway plumber gaps * Update changelog.txt
2023-11-17 12:23:05 +01:00
{ 168, 20 }, { 169, 20 },
{ 46, 51 }, { 58, 159 }, { 71, 201 }, { 126, 15 }, { 190, 6 }
},
OWNERSHIP_AVAILABLE, true);
// clang-format on
}
else if (String::Equals(_s6.ScenarioFilename, "Six Flags over Texas.SC6"))
{
// clang-format off
FixLandOwnershipTilesWithOwnership(
{
{ 85, 80 },
{ 86, 79 },
{ 96, 71 }, { 97, 71 },
{ 90, 42 }, { 90, 43 }, { 90, 44 }, { 90, 45 },
{ 87, 73 }, { 87, 74 }, { 87, 75 }, { 87, 76 }, { 87, 77 }, { 87, 78 }, { 88, 73 }, { 88, 74 }, { 88, 75 }, { 88, 76 },
{ 89, 73 }, { 89, 74 }, { 89, 75 }, { 90, 73 }, { 90, 74 }, { 90, 75 }, { 91, 73 }, { 92, 73 },
},
OWNERSHIP_CONSTRUCTION_RIGHTS_OWNED, true);
// clang-format on
}
else if (String::Equals(_s6.ScenarioFilename, "Great Wall of China Tourism Enhancement.SC6"))
{
//clang-format off
FixLandOwnershipTilesWithOwnership(
{
{ 127, 31 },
},
OWNERSHIP_OWNED);
//clang-format on
}
2023-01-22 20:16:41 +01:00
else if (String::Equals(_s6.ScenarioFilename, "North America - Grand Canyon.SC6"))
{
// clang-format off
Fix #17774: gaps and errors in park boundaries and construction rights for RCT1 and RCT2 scenarios (#19657) * Update S6Importer.cpp * clang format error. Added changelog entry. * Update S6Importer.cpp * Added fixes for RCT1 scenarios The issues in Katie's Dreamland, Utopia Park, Urban Park, Pleasure Island, and Fort Anachronism listed in issue #17774 have been now dealt with. * Added land for Cradle's underwater path. * Update changelog.txt * Updated changelog. * specify text for path fix in Cradle * Update S6Importer.cpp * More missing tiles in Coastal Reclaim & Salvage * Update S6Importer.cpp * Update S6Importer.cpp * missed tile in stone age * Classic compatibility Added edit compatibility for classic scenarios on rct2 maps. * Update changelog.txt * Update S6Importer.cpp * Update S6Importer.cpp * Update S6Importer.cpp * Fun At The Beach Fixed errant tiles in Fun at the Beach. * Update S6Importer.cpp * Update S6Importer.cpp * Extreme Heights Fix missing tiles along edge of Extreme Heights park boundary; should run to 1 tile from the edge of the map almost all the way around. * Final Set of Changes Did a quick run-through of all the maps looking for any possible missed spots. I did find a series of spots, some clearly meant to be owned, and others that I'm a bit less than sure about. For now, I've commented out the spots that I don't feel are strictly necessary to have included, while the remaining ones I feel are necessary. * Update S4Importer.cpp * add optional fixes un-commented the extra changes; they are now included. * Update changelog.txt * fix clang format error * Update changelog.txt * Update S6Importer.cpp OOB underground path * Update S6Importer.cpp * Update S6Importer.cpp * above runaway plumber gaps * Update changelog.txt
2023-11-17 12:23:05 +01:00
FixLandOwnershipTilesWithOwnership(
{
{ 42, 147 }, { 58, 122 }, { 87, 147 }
},
OWNERSHIP_AVAILABLE, true);
FixLandOwnershipTilesWithOwnership(
{
{ 128, 90 },
{ 135, 91 }, { 136, 91 },
{ 129, 90 }, { 130, 90 }, { 131, 90 }, { 132, 90 },
{ 137, 92 }, { 138, 92 }, { 139, 92 }, { 140, 92 },
{ 125, 88 }, { 126, 89 }, { 127, 91 }, { 127, 92 }, { 127, 93 },
{ 47, 85 }, { 48, 85 },
{ 32, 97 },
},
OWNERSHIP_CONSTRUCTION_RIGHTS_AVAILABLE, true);
FixLandOwnershipTilesWithOwnership(
{
{ 98, 64 }, { 98, 65 }, { 98, 66 },
{ 96, 84 },
},
OWNERSHIP_CONSTRUCTION_RIGHTS_OWNED, true);
// clang-format on
}
else if (
Fix #17774: gaps and errors in park boundaries and construction rights for RCT1 and RCT2 scenarios (#19657) * Update S6Importer.cpp * clang format error. Added changelog entry. * Update S6Importer.cpp * Added fixes for RCT1 scenarios The issues in Katie's Dreamland, Utopia Park, Urban Park, Pleasure Island, and Fort Anachronism listed in issue #17774 have been now dealt with. * Added land for Cradle's underwater path. * Update changelog.txt * Updated changelog. * specify text for path fix in Cradle * Update S6Importer.cpp * More missing tiles in Coastal Reclaim & Salvage * Update S6Importer.cpp * Update S6Importer.cpp * missed tile in stone age * Classic compatibility Added edit compatibility for classic scenarios on rct2 maps. * Update changelog.txt * Update S6Importer.cpp * Update S6Importer.cpp * Update S6Importer.cpp * Fun At The Beach Fixed errant tiles in Fun at the Beach. * Update S6Importer.cpp * Update S6Importer.cpp * Extreme Heights Fix missing tiles along edge of Extreme Heights park boundary; should run to 1 tile from the edge of the map almost all the way around. * Final Set of Changes Did a quick run-through of all the maps looking for any possible missed spots. I did find a series of spots, some clearly meant to be owned, and others that I'm a bit less than sure about. For now, I've commented out the spots that I don't feel are strictly necessary to have included, while the remaining ones I feel are necessary. * Update S4Importer.cpp * add optional fixes un-commented the extra changes; they are now included. * Update changelog.txt * fix clang format error * Update changelog.txt * Update S6Importer.cpp OOB underground path * Update S6Importer.cpp * Update S6Importer.cpp * above runaway plumber gaps * Update changelog.txt
2023-11-17 12:23:05 +01:00
String::IEquals(gScenarioFileName, "Asia - Maharaja Palace.SC6")
|| String::IEquals(gScenarioFileName, "asia - maharaja palace.sea"))
{
// clang-format off
FixLandOwnershipTilesWithOwnership(
{
Fix #17774: gaps and errors in park boundaries and construction rights for RCT1 and RCT2 scenarios (#19657) * Update S6Importer.cpp * clang format error. Added changelog entry. * Update S6Importer.cpp * Added fixes for RCT1 scenarios The issues in Katie's Dreamland, Utopia Park, Urban Park, Pleasure Island, and Fort Anachronism listed in issue #17774 have been now dealt with. * Added land for Cradle's underwater path. * Update changelog.txt * Updated changelog. * specify text for path fix in Cradle * Update S6Importer.cpp * More missing tiles in Coastal Reclaim & Salvage * Update S6Importer.cpp * Update S6Importer.cpp * missed tile in stone age * Classic compatibility Added edit compatibility for classic scenarios on rct2 maps. * Update changelog.txt * Update S6Importer.cpp * Update S6Importer.cpp * Update S6Importer.cpp * Fun At The Beach Fixed errant tiles in Fun at the Beach. * Update S6Importer.cpp * Update S6Importer.cpp * Extreme Heights Fix missing tiles along edge of Extreme Heights park boundary; should run to 1 tile from the edge of the map almost all the way around. * Final Set of Changes Did a quick run-through of all the maps looking for any possible missed spots. I did find a series of spots, some clearly meant to be owned, and others that I'm a bit less than sure about. For now, I've commented out the spots that I don't feel are strictly necessary to have included, while the remaining ones I feel are necessary. * Update S4Importer.cpp * add optional fixes un-commented the extra changes; they are now included. * Update changelog.txt * fix clang format error * Update changelog.txt * Update S6Importer.cpp OOB underground path * Update S6Importer.cpp * Update S6Importer.cpp * above runaway plumber gaps * Update changelog.txt
2023-11-17 12:23:05 +01:00
{ 43, 65 },
{ 69, 41 },
{ 74, 2 },
{ 90, 19 }, { 90, 20 },
{ 65, 40 }, { 66, 40 }, { 67, 40 },
{ 62, 24 }, { 63, 24 }, { 64, 24 }, { 65, 24 }, { 65, 25 },
{ 98, 19 }, { 98, 20 }, { 98, 21 }, { 99, 19 }, { 99, 20 }, { 99, 21 },
{ 51, 28 }, { 52, 28 }, { 53, 28 }, { 54, 28 }, { 55, 28 }, { 56, 28 }, { 51, 29 }, { 52, 29 }, { 53, 29 }, { 54, 29 },
{ 37, 27 }, { 37, 28 }, { 37, 29 }, { 38, 26 }, { 38, 27 }, { 38, 28 }, { 38, 29 }, { 39, 26 }, { 39, 27 }, { 39, 28 }, { 39, 29 },
{ 40, 26 }, { 40, 27 }, { 40, 28 }, { 40, 29 }, { 40, 30 }, { 41, 26 }, { 41, 27 }, { 41, 28 }, { 41, 29 }, { 42, 26 }, { 42, 27 },
{ 42, 28 }, { 42, 29 }, { 43, 25 }, { 43, 26 }, { 43, 27 }, { 43, 28 }, { 43, 29 },
},
OWNERSHIP_AVAILABLE, true);
// clang-format on
}
Fix #17774: gaps and errors in park boundaries and construction rights for RCT1 and RCT2 scenarios (#19657) * Update S6Importer.cpp * clang format error. Added changelog entry. * Update S6Importer.cpp * Added fixes for RCT1 scenarios The issues in Katie's Dreamland, Utopia Park, Urban Park, Pleasure Island, and Fort Anachronism listed in issue #17774 have been now dealt with. * Added land for Cradle's underwater path. * Update changelog.txt * Updated changelog. * specify text for path fix in Cradle * Update S6Importer.cpp * More missing tiles in Coastal Reclaim & Salvage * Update S6Importer.cpp * Update S6Importer.cpp * missed tile in stone age * Classic compatibility Added edit compatibility for classic scenarios on rct2 maps. * Update changelog.txt * Update S6Importer.cpp * Update S6Importer.cpp * Update S6Importer.cpp * Fun At The Beach Fixed errant tiles in Fun at the Beach. * Update S6Importer.cpp * Update S6Importer.cpp * Extreme Heights Fix missing tiles along edge of Extreme Heights park boundary; should run to 1 tile from the edge of the map almost all the way around. * Final Set of Changes Did a quick run-through of all the maps looking for any possible missed spots. I did find a series of spots, some clearly meant to be owned, and others that I'm a bit less than sure about. For now, I've commented out the spots that I don't feel are strictly necessary to have included, while the remaining ones I feel are necessary. * Update S4Importer.cpp * add optional fixes un-commented the extra changes; they are now included. * Update changelog.txt * fix clang format error * Update changelog.txt * Update S6Importer.cpp OOB underground path * Update S6Importer.cpp * Update S6Importer.cpp * above runaway plumber gaps * Update changelog.txt
2023-11-17 12:23:05 +01:00
else if (
String::IEquals(gScenarioFileName, "South America - Inca Lost City.SC6")
|| String::IEquals(gScenarioFileName, "south america - inca lost city.sea"))
{
Fix #17774: gaps and errors in park boundaries and construction rights for RCT1 and RCT2 scenarios (#19657) * Update S6Importer.cpp * clang format error. Added changelog entry. * Update S6Importer.cpp * Added fixes for RCT1 scenarios The issues in Katie's Dreamland, Utopia Park, Urban Park, Pleasure Island, and Fort Anachronism listed in issue #17774 have been now dealt with. * Added land for Cradle's underwater path. * Update changelog.txt * Updated changelog. * specify text for path fix in Cradle * Update S6Importer.cpp * More missing tiles in Coastal Reclaim & Salvage * Update S6Importer.cpp * Update S6Importer.cpp * missed tile in stone age * Classic compatibility Added edit compatibility for classic scenarios on rct2 maps. * Update changelog.txt * Update S6Importer.cpp * Update S6Importer.cpp * Update S6Importer.cpp * Fun At The Beach Fixed errant tiles in Fun at the Beach. * Update S6Importer.cpp * Update S6Importer.cpp * Extreme Heights Fix missing tiles along edge of Extreme Heights park boundary; should run to 1 tile from the edge of the map almost all the way around. * Final Set of Changes Did a quick run-through of all the maps looking for any possible missed spots. I did find a series of spots, some clearly meant to be owned, and others that I'm a bit less than sure about. For now, I've commented out the spots that I don't feel are strictly necessary to have included, while the remaining ones I feel are necessary. * Update S4Importer.cpp * add optional fixes un-commented the extra changes; they are now included. * Update changelog.txt * fix clang format error * Update changelog.txt * Update S6Importer.cpp OOB underground path * Update S6Importer.cpp * Update S6Importer.cpp * above runaway plumber gaps * Update changelog.txt
2023-11-17 12:23:05 +01:00
// clang-format off
FixLandOwnershipTilesWithOwnership(
{
{ 15, 59 },
},
OWNERSHIP_UNOWNED);
FixLandOwnershipTilesWithOwnership(
{
{ 11, 64 }, { 11, 65 }, { 11, 66 },
{ 13, 68 }, { 13, 69 },
{ 14, 69 },
{ 15, 59 },
Fix #17774: gaps and errors in park boundaries and construction rights for RCT1 and RCT2 scenarios (#19657) * Update S6Importer.cpp * clang format error. Added changelog entry. * Update S6Importer.cpp * Added fixes for RCT1 scenarios The issues in Katie's Dreamland, Utopia Park, Urban Park, Pleasure Island, and Fort Anachronism listed in issue #17774 have been now dealt with. * Added land for Cradle's underwater path. * Update changelog.txt * Updated changelog. * specify text for path fix in Cradle * Update S6Importer.cpp * More missing tiles in Coastal Reclaim & Salvage * Update S6Importer.cpp * Update S6Importer.cpp * missed tile in stone age * Classic compatibility Added edit compatibility for classic scenarios on rct2 maps. * Update changelog.txt * Update S6Importer.cpp * Update S6Importer.cpp * Update S6Importer.cpp * Fun At The Beach Fixed errant tiles in Fun at the Beach. * Update S6Importer.cpp * Update S6Importer.cpp * Extreme Heights Fix missing tiles along edge of Extreme Heights park boundary; should run to 1 tile from the edge of the map almost all the way around. * Final Set of Changes Did a quick run-through of all the maps looking for any possible missed spots. I did find a series of spots, some clearly meant to be owned, and others that I'm a bit less than sure about. For now, I've commented out the spots that I don't feel are strictly necessary to have included, while the remaining ones I feel are necessary. * Update S4Importer.cpp * add optional fixes un-commented the extra changes; they are now included. * Update changelog.txt * fix clang format error * Update changelog.txt * Update S6Importer.cpp OOB underground path * Update S6Importer.cpp * Update S6Importer.cpp * above runaway plumber gaps * Update changelog.txt
2023-11-17 12:23:05 +01:00
{ 55, 60 },
{ 61, 6 },
{ 86, 63 },
{ 84, 22 }, { 84, 23 },
{ 83, 77 }, { 84, 77 }, { 84, 78 },
{ 44, 61 }, { 45, 61 }, { 46, 61 }, { 45, 62 },
},
OWNERSHIP_CONSTRUCTION_RIGHTS_OWNED, true);
// clang-format on
}
else if (
String::Equals(_s6.ScenarioFilename, "WW Africa - Oasis.SC6", true)
|| String::Equals(_s6.ScenarioFilename, "Africa - Oasis.SC6", true))
{
// clang-format off
FixLandOwnershipTilesWithOwnership(
{
{ 61, 35 },
},
OWNERSHIP_UNOWNED);
FixLandOwnershipTilesWithOwnership(
{
{ 46, 87 },
},
OWNERSHIP_OWNED);
FixLandOwnershipTilesWithOwnership(
{
{ 140, 58 }, { 141, 58 }, { 142, 58 }, { 143, 58 }, { 144, 58 }, { 145, 58 }, { 146, 58 }, { 147, 58 },
{ 140, 74 }, { 141, 74 }, { 142, 74 }, { 143, 74 }, { 144, 74 }, { 145, 74 }, { 146, 74 }, { 147, 74 },
},
OWNERSHIP_CONSTRUCTION_RIGHTS_OWNED, true);
Fix #17774: gaps and errors in park boundaries and construction rights for RCT1 and RCT2 scenarios (#19657) * Update S6Importer.cpp * clang format error. Added changelog entry. * Update S6Importer.cpp * Added fixes for RCT1 scenarios The issues in Katie's Dreamland, Utopia Park, Urban Park, Pleasure Island, and Fort Anachronism listed in issue #17774 have been now dealt with. * Added land for Cradle's underwater path. * Update changelog.txt * Updated changelog. * specify text for path fix in Cradle * Update S6Importer.cpp * More missing tiles in Coastal Reclaim & Salvage * Update S6Importer.cpp * Update S6Importer.cpp * missed tile in stone age * Classic compatibility Added edit compatibility for classic scenarios on rct2 maps. * Update changelog.txt * Update S6Importer.cpp * Update S6Importer.cpp * Update S6Importer.cpp * Fun At The Beach Fixed errant tiles in Fun at the Beach. * Update S6Importer.cpp * Update S6Importer.cpp * Extreme Heights Fix missing tiles along edge of Extreme Heights park boundary; should run to 1 tile from the edge of the map almost all the way around. * Final Set of Changes Did a quick run-through of all the maps looking for any possible missed spots. I did find a series of spots, some clearly meant to be owned, and others that I'm a bit less than sure about. For now, I've commented out the spots that I don't feel are strictly necessary to have included, while the remaining ones I feel are necessary. * Update S4Importer.cpp * add optional fixes un-commented the extra changes; they are now included. * Update changelog.txt * fix clang format error * Update changelog.txt * Update S6Importer.cpp OOB underground path * Update S6Importer.cpp * Update S6Importer.cpp * above runaway plumber gaps * Update changelog.txt
2023-11-17 12:23:05 +01:00
// clang-format on
}
else if (
String::IEquals(gScenarioFileName, "Antarctic - Ecological Salvage.SC6")
|| String::IEquals(gScenarioFileName, "antarctic - ecological salvage.sea"))
{
// clang-format off
FixLandOwnershipTilesWithOwnership(
{
{ 83, 117 }, { 84, 117 },
{ 106, 106 }, { 106, 107 },
},
OWNERSHIP_UNOWNED);
FixLandOwnershipTilesWithOwnership(
{
{ 90, 8 },
{ 2, 26 }, { 2, 27 },
{ 83, 117 }, { 84, 117 },
{ 96, 2 }, { 97, 2 },
{ 106, 106 }, { 106, 107 },
},
OWNERSHIP_AVAILABLE, true);
// clang-format on
}
else if (
String::Equals(_s6.ScenarioFilename, "WW Asia - Japanese Coastal Reclaim.SC6", true)
|| String::Equals(_s6.ScenarioFilename, "Asia - Japanese Coastal Reclaim.SC6", true))
{
// clang-format off
FixLandOwnershipTilesWithOwnership(
{
{ 7, 29 },
{ 24, 14 }, { 24, 15 }, { 24, 16 },
{ 25, 13 }, { 25, 14 }, { 25, 15 }, { 25, 16 }, { 25, 17 },
{ 26, 12 }, { 26, 13 }, { 26, 14 }, { 26, 15 }, { 26, 16 }, { 26, 17 }, { 26, 18 }, { 26, 19 }, { 26, 20 },
{ 27, 11 }, { 27, 12 }, { 27, 13 }, { 27, 14 }, { 27, 15 }, { 27, 16 }, { 27, 17 }, { 27, 18 }, { 27, 19 }, { 27, 20 }, { 27, 21 },
{ 28, 8 }, { 28, 9 }, { 28, 10 }, { 28, 11 }, { 28, 12 }, { 28, 13 }, { 28, 14 }, { 28, 15 }, { 28, 16 }, { 28, 17 }, { 28, 18 }, { 28, 19 }, { 28, 20 }, { 28, 21 },
{ 29, 6 }, { 29, 7 }, { 29, 8 }, { 29, 9 }, { 29, 10 }, { 29, 11 }, { 29, 12 }, { 29, 13 }, { 29, 14 }, { 29, 15 }, { 29, 16 }, { 29, 17 }, { 29, 18 }, { 29, 19 }, { 29, 20 }, { 29, 21 },
{ 30, 2 }, { 30, 3 }, { 30, 4 }, { 30, 5 }, { 30, 6 }, { 30, 7 }, { 30, 8 }, { 30, 9 }, { 30, 10 }, { 30, 11 }, { 30, 12 }, { 30, 17 }, { 30, 18 }, { 30, 19 }, { 30, 20 }, { 30, 21 },
{ 31, 2 }, { 31, 3 }, { 31, 4 }, { 31, 5 }, { 31, 6 }, { 31, 7 }, { 31, 8 }, { 31, 9 }, { 31, 10 }, { 31, 11 }, { 31, 19 }, { 31, 20 }, { 31, 21 },
{ 32, 2 }, { 32, 3 }, { 32, 4 }, { 32, 5 }, { 32, 6 }, { 32, 7 }, { 32, 8 }, { 32, 20 }, { 32, 21 },
{ 33, 2 }, { 33, 3 }, { 33, 4 }, { 33, 5 }, { 33, 6 }, { 33, 7 }, { 33, 20 }, { 33, 21 },
{ 34, 2 }, { 34, 3 }, { 34, 4 }, { 34, 20 }, { 34, 21 },
{ 35, 21 },
},
OWNERSHIP_OWNED);
Fix #17774: gaps and errors in park boundaries and construction rights for RCT1 and RCT2 scenarios (#19657) * Update S6Importer.cpp * clang format error. Added changelog entry. * Update S6Importer.cpp * Added fixes for RCT1 scenarios The issues in Katie's Dreamland, Utopia Park, Urban Park, Pleasure Island, and Fort Anachronism listed in issue #17774 have been now dealt with. * Added land for Cradle's underwater path. * Update changelog.txt * Updated changelog. * specify text for path fix in Cradle * Update S6Importer.cpp * More missing tiles in Coastal Reclaim & Salvage * Update S6Importer.cpp * Update S6Importer.cpp * missed tile in stone age * Classic compatibility Added edit compatibility for classic scenarios on rct2 maps. * Update changelog.txt * Update S6Importer.cpp * Update S6Importer.cpp * Update S6Importer.cpp * Fun At The Beach Fixed errant tiles in Fun at the Beach. * Update S6Importer.cpp * Update S6Importer.cpp * Extreme Heights Fix missing tiles along edge of Extreme Heights park boundary; should run to 1 tile from the edge of the map almost all the way around. * Final Set of Changes Did a quick run-through of all the maps looking for any possible missed spots. I did find a series of spots, some clearly meant to be owned, and others that I'm a bit less than sure about. For now, I've commented out the spots that I don't feel are strictly necessary to have included, while the remaining ones I feel are necessary. * Update S4Importer.cpp * add optional fixes un-commented the extra changes; they are now included. * Update changelog.txt * fix clang format error * Update changelog.txt * Update S6Importer.cpp OOB underground path * Update S6Importer.cpp * Update S6Importer.cpp * above runaway plumber gaps * Update changelog.txt
2023-11-17 12:23:05 +01:00
FixLandOwnershipTilesWithOwnership(
{
{ 2, 30 }, { 3, 30 }, { 4, 30 },
Fix #17774: gaps and errors in park boundaries and construction rights for RCT1 and RCT2 scenarios (#19657) * Update S6Importer.cpp * clang format error. Added changelog entry. * Update S6Importer.cpp * Added fixes for RCT1 scenarios The issues in Katie's Dreamland, Utopia Park, Urban Park, Pleasure Island, and Fort Anachronism listed in issue #17774 have been now dealt with. * Added land for Cradle's underwater path. * Update changelog.txt * Updated changelog. * specify text for path fix in Cradle * Update S6Importer.cpp * More missing tiles in Coastal Reclaim & Salvage * Update S6Importer.cpp * Update S6Importer.cpp * missed tile in stone age * Classic compatibility Added edit compatibility for classic scenarios on rct2 maps. * Update changelog.txt * Update S6Importer.cpp * Update S6Importer.cpp * Update S6Importer.cpp * Fun At The Beach Fixed errant tiles in Fun at the Beach. * Update S6Importer.cpp * Update S6Importer.cpp * Extreme Heights Fix missing tiles along edge of Extreme Heights park boundary; should run to 1 tile from the edge of the map almost all the way around. * Final Set of Changes Did a quick run-through of all the maps looking for any possible missed spots. I did find a series of spots, some clearly meant to be owned, and others that I'm a bit less than sure about. For now, I've commented out the spots that I don't feel are strictly necessary to have included, while the remaining ones I feel are necessary. * Update S4Importer.cpp * add optional fixes un-commented the extra changes; they are now included. * Update changelog.txt * fix clang format error * Update changelog.txt * Update S6Importer.cpp OOB underground path * Update S6Importer.cpp * Update S6Importer.cpp * above runaway plumber gaps * Update changelog.txt
2023-11-17 12:23:05 +01:00
{ 25, 23 },
},
OWNERSHIP_CONSTRUCTION_RIGHTS_OWNED, true);
FixLandOwnershipTilesWithOwnership(
{
{ 26, 116 },
{ 61, 110 },
{ 64, 113 }, { 64, 114 }, { 64, 115 },
},
OWNERSHIP_CONSTRUCTION_RIGHTS_AVAILABLE, true);
FixLandOwnershipTilesWithOwnership(
{
{ 6, 100 }, { 7, 100 }, { 8, 100 }, { 9, 100 }, { 10, 100 }, { 15, 100 }, { 16, 100 },
{ 6, 101 }, { 7, 101 }, { 8, 101 }, { 9, 101 }, { 10, 101 }, { 15, 101 }, { 16, 101 },
{ 6, 102 }, { 7, 102 }, { 8, 102 }, { 9, 102 }, { 10, 102 }, { 14, 102 }, { 15, 102 }, { 16, 102 },
{ 6, 103 }, { 7, 103 }, { 8, 103 }, { 9, 103 }, { 10, 103 }, { 12, 103 }, { 14, 103 }, { 15, 103 }, { 16, 103 },
{ 6, 104 }, { 7, 104 }, { 8, 104 }, { 9, 104 }, { 10, 104 }, { 14, 104 }, { 15, 104 }, { 16, 104 },
{ 6, 105 }, { 7, 105 }, { 8, 105 }, { 9, 105 }, { 10, 105 }, { 11, 105 }, { 12, 105 }, { 13, 105 }, { 14, 105 }, { 15, 105 }, { 16, 105 },
Fix #17774: gaps and errors in park boundaries and construction rights for RCT1 and RCT2 scenarios (#19657) * Update S6Importer.cpp * clang format error. Added changelog entry. * Update S6Importer.cpp * Added fixes for RCT1 scenarios The issues in Katie's Dreamland, Utopia Park, Urban Park, Pleasure Island, and Fort Anachronism listed in issue #17774 have been now dealt with. * Added land for Cradle's underwater path. * Update changelog.txt * Updated changelog. * specify text for path fix in Cradle * Update S6Importer.cpp * More missing tiles in Coastal Reclaim & Salvage * Update S6Importer.cpp * Update S6Importer.cpp * missed tile in stone age * Classic compatibility Added edit compatibility for classic scenarios on rct2 maps. * Update changelog.txt * Update S6Importer.cpp * Update S6Importer.cpp * Update S6Importer.cpp * Fun At The Beach Fixed errant tiles in Fun at the Beach. * Update S6Importer.cpp * Update S6Importer.cpp * Extreme Heights Fix missing tiles along edge of Extreme Heights park boundary; should run to 1 tile from the edge of the map almost all the way around. * Final Set of Changes Did a quick run-through of all the maps looking for any possible missed spots. I did find a series of spots, some clearly meant to be owned, and others that I'm a bit less than sure about. For now, I've commented out the spots that I don't feel are strictly necessary to have included, while the remaining ones I feel are necessary. * Update S4Importer.cpp * add optional fixes un-commented the extra changes; they are now included. * Update changelog.txt * fix clang format error * Update changelog.txt * Update S6Importer.cpp OOB underground path * Update S6Importer.cpp * Update S6Importer.cpp * above runaway plumber gaps * Update changelog.txt
2023-11-17 12:23:05 +01:00
{ 122, 78 }, { 122, 79 },
{ 111, 122 }, { 112, 122 }, { 113, 122 },
{ 120, 15 }, { 121, 15 }, { 122, 15 },
{ 58, 101 }, { 59, 101 }, { 59, 102 }, { 59, 103 }, { 59, 104 }, { 59, 105 }, { 59, 106 }, { 59, 107 }, { 60, 104 }, { 60, 105 },
{ 60, 106 }, { 61, 104 }, { 61, 105 },
{ 121, 105 }, { 121, 106 }, { 121, 107 }, { 122, 99 }, { 122, 100 }, { 122, 101 }, { 122, 102 }, { 122, 103 }, { 122, 104 }, { 122, 105 },
{ 122, 106 }, { 122, 107 }, { 122, 108 }, { 122, 109 }, { 122, 110 }, { 122, 111 }, { 122, 112 }, { 122, 113 }, { 122, 114 }, { 122, 115 },
{ 122, 116 }, { 122, 117 }, { 122, 118 },
},
OWNERSHIP_AVAILABLE, true);
// clang-format on
}
else if (String::Equals(_s6.ScenarioFilename, "Australasia - Fun at the Beach.SC6"))
{
// clang-format off
FixLandOwnershipTilesWithOwnership(
{
{ 63, 97 },
{ 64, 97 },
},
OWNERSHIP_UNOWNED);
FixLandOwnershipTilesWithOwnership(
{
{ 63, 97 },
{ 64, 97 },
},
OWNERSHIP_AVAILABLE, true);
// clang-format on
}
else if (String::Equals(_s6.ScenarioFilename, "Europe - Renovation.SC6"))
{
// clang-format off
FixLandOwnershipTilesWithOwnership(
{
{ 12, 21 },
},
OWNERSHIP_OWNED);
// clang-format on
}
else if (
String::IEquals(gScenarioFileName, "N America - Extreme Hawaiian Island.SC6")
|| String::IEquals(gScenarioFileName, "n america - extreme hawaiian island.sea"))
{
Fix #17774: gaps and errors in park boundaries and construction rights for RCT1 and RCT2 scenarios (#19657) * Update S6Importer.cpp * clang format error. Added changelog entry. * Update S6Importer.cpp * Added fixes for RCT1 scenarios The issues in Katie's Dreamland, Utopia Park, Urban Park, Pleasure Island, and Fort Anachronism listed in issue #17774 have been now dealt with. * Added land for Cradle's underwater path. * Update changelog.txt * Updated changelog. * specify text for path fix in Cradle * Update S6Importer.cpp * More missing tiles in Coastal Reclaim & Salvage * Update S6Importer.cpp * Update S6Importer.cpp * missed tile in stone age * Classic compatibility Added edit compatibility for classic scenarios on rct2 maps. * Update changelog.txt * Update S6Importer.cpp * Update S6Importer.cpp * Update S6Importer.cpp * Fun At The Beach Fixed errant tiles in Fun at the Beach. * Update S6Importer.cpp * Update S6Importer.cpp * Extreme Heights Fix missing tiles along edge of Extreme Heights park boundary; should run to 1 tile from the edge of the map almost all the way around. * Final Set of Changes Did a quick run-through of all the maps looking for any possible missed spots. I did find a series of spots, some clearly meant to be owned, and others that I'm a bit less than sure about. For now, I've commented out the spots that I don't feel are strictly necessary to have included, while the remaining ones I feel are necessary. * Update S4Importer.cpp * add optional fixes un-commented the extra changes; they are now included. * Update changelog.txt * fix clang format error * Update changelog.txt * Update S6Importer.cpp OOB underground path * Update S6Importer.cpp * Update S6Importer.cpp * above runaway plumber gaps * Update changelog.txt
2023-11-17 12:23:05 +01:00
// clang-format off
FixLandOwnershipTilesWithOwnership(
Fix #17774: gaps and errors in park boundaries and construction rights for RCT1 and RCT2 scenarios (#19657) * Update S6Importer.cpp * clang format error. Added changelog entry. * Update S6Importer.cpp * Added fixes for RCT1 scenarios The issues in Katie's Dreamland, Utopia Park, Urban Park, Pleasure Island, and Fort Anachronism listed in issue #17774 have been now dealt with. * Added land for Cradle's underwater path. * Update changelog.txt * Updated changelog. * specify text for path fix in Cradle * Update S6Importer.cpp * More missing tiles in Coastal Reclaim & Salvage * Update S6Importer.cpp * Update S6Importer.cpp * missed tile in stone age * Classic compatibility Added edit compatibility for classic scenarios on rct2 maps. * Update changelog.txt * Update S6Importer.cpp * Update S6Importer.cpp * Update S6Importer.cpp * Fun At The Beach Fixed errant tiles in Fun at the Beach. * Update S6Importer.cpp * Update S6Importer.cpp * Extreme Heights Fix missing tiles along edge of Extreme Heights park boundary; should run to 1 tile from the edge of the map almost all the way around. * Final Set of Changes Did a quick run-through of all the maps looking for any possible missed spots. I did find a series of spots, some clearly meant to be owned, and others that I'm a bit less than sure about. For now, I've commented out the spots that I don't feel are strictly necessary to have included, while the remaining ones I feel are necessary. * Update S4Importer.cpp * add optional fixes un-commented the extra changes; they are now included. * Update changelog.txt * fix clang format error * Update changelog.txt * Update S6Importer.cpp OOB underground path * Update S6Importer.cpp * Update S6Importer.cpp * above runaway plumber gaps * Update changelog.txt
2023-11-17 12:23:05 +01:00
{
{ 132, 124 },
{ 133, 124 },
{ 133, 125 },
{ 133, 126 },
{ 119, 35 },
{ 132, 62 },
{ 133, 66 },
{ 133, 67 },
{ 136, 71 },
{ 87, 33 },
{ 87, 34 },
{ 90, 36 },
{ 91, 36 },
},
OWNERSHIP_OWNED);
// We set the doNotDowngrade flag for cases where the player has used a cheat to own all land.
FixLandOwnershipTilesWithOwnership(
{
{ 49, 99 },
{ 50, 99 },
{ 88, 110 },
},
OWNERSHIP_AVAILABLE, true);
Fix #17774: gaps and errors in park boundaries and construction rights for RCT1 and RCT2 scenarios (#19657) * Update S6Importer.cpp * clang format error. Added changelog entry. * Update S6Importer.cpp * Added fixes for RCT1 scenarios The issues in Katie's Dreamland, Utopia Park, Urban Park, Pleasure Island, and Fort Anachronism listed in issue #17774 have been now dealt with. * Added land for Cradle's underwater path. * Update changelog.txt * Updated changelog. * specify text for path fix in Cradle * Update S6Importer.cpp * More missing tiles in Coastal Reclaim & Salvage * Update S6Importer.cpp * Update S6Importer.cpp * missed tile in stone age * Classic compatibility Added edit compatibility for classic scenarios on rct2 maps. * Update changelog.txt * Update S6Importer.cpp * Update S6Importer.cpp * Update S6Importer.cpp * Fun At The Beach Fixed errant tiles in Fun at the Beach. * Update S6Importer.cpp * Update S6Importer.cpp * Extreme Heights Fix missing tiles along edge of Extreme Heights park boundary; should run to 1 tile from the edge of the map almost all the way around. * Final Set of Changes Did a quick run-through of all the maps looking for any possible missed spots. I did find a series of spots, some clearly meant to be owned, and others that I'm a bit less than sure about. For now, I've commented out the spots that I don't feel are strictly necessary to have included, while the remaining ones I feel are necessary. * Update S4Importer.cpp * add optional fixes un-commented the extra changes; they are now included. * Update changelog.txt * fix clang format error * Update changelog.txt * Update S6Importer.cpp OOB underground path * Update S6Importer.cpp * Update S6Importer.cpp * above runaway plumber gaps * Update changelog.txt
2023-11-17 12:23:05 +01:00
// clang-format on
}
else if (String::Equals(_s6.ScenarioFilename, "Dark Age - Robin Hood.SC6"))
{
// clang-format off
FixLandOwnershipTilesWithOwnership(
{
{ 104, 64 },
{ 111, 114 }, { 112, 114 },
},
OWNERSHIP_AVAILABLE, true);
// clang-format on
}
else if (
String::IEquals(gScenarioFileName, "Dark Age - Castle.SC6")
|| String::IEquals(gScenarioFileName, "dark age - castle.sea"))
{
// clang-format off
FixLandOwnershipTilesWithOwnership(
{
{ 61, 15 },
{ 62, 16 },
{ 34, 51 }, { 35, 51 }, { 35, 50 },
{ 34, 72 }, { 35, 72 }, { 35, 73 },
{ 66, 19 }, { 66, 20 }, { 67, 20 },
{ 75, 85 }, { 76, 85 }, { 76, 86 },
{ 59, 18 }, { 60, 18 }, { 60, 17 }, { 61, 17 },
Fix #17774: gaps and errors in park boundaries and construction rights for RCT1 and RCT2 scenarios (#19657) * Update S6Importer.cpp * clang format error. Added changelog entry. * Update S6Importer.cpp * Added fixes for RCT1 scenarios The issues in Katie's Dreamland, Utopia Park, Urban Park, Pleasure Island, and Fort Anachronism listed in issue #17774 have been now dealt with. * Added land for Cradle's underwater path. * Update changelog.txt * Updated changelog. * specify text for path fix in Cradle * Update S6Importer.cpp * More missing tiles in Coastal Reclaim & Salvage * Update S6Importer.cpp * Update S6Importer.cpp * missed tile in stone age * Classic compatibility Added edit compatibility for classic scenarios on rct2 maps. * Update changelog.txt * Update S6Importer.cpp * Update S6Importer.cpp * Update S6Importer.cpp * Fun At The Beach Fixed errant tiles in Fun at the Beach. * Update S6Importer.cpp * Update S6Importer.cpp * Extreme Heights Fix missing tiles along edge of Extreme Heights park boundary; should run to 1 tile from the edge of the map almost all the way around. * Final Set of Changes Did a quick run-through of all the maps looking for any possible missed spots. I did find a series of spots, some clearly meant to be owned, and others that I'm a bit less than sure about. For now, I've commented out the spots that I don't feel are strictly necessary to have included, while the remaining ones I feel are necessary. * Update S4Importer.cpp * add optional fixes un-commented the extra changes; they are now included. * Update changelog.txt * fix clang format error * Update changelog.txt * Update S6Importer.cpp OOB underground path * Update S6Importer.cpp * Update S6Importer.cpp * above runaway plumber gaps * Update changelog.txt
2023-11-17 12:23:05 +01:00
},
OWNERSHIP_OWNED);
FixLandOwnershipTilesWithOwnership(
{
{ 86, 69 }, { 86, 70 }
},
OWNERSHIP_CONSTRUCTION_RIGHTS_OWNED, true);
// clang-format on
}
else if (String::Equals(_s6.ScenarioFilename, "Mythological - Animatronic Film Set.SC6"))
{
// clang-format off
FixLandOwnershipTilesWithOwnership(
{
{ 44, 51 },
{ 47, 50 },
{ 48, 47 },
},
OWNERSHIP_CONSTRUCTION_RIGHTS_OWNED, true);
// clang-format on
}
else if (String::Equals(_s6.ScenarioFilename, "Prehistoric - Jurassic Safari.SC6"))
{
// clang-format off
FixLandOwnershipTilesWithOwnership(
{
{ 28, 95 },
},
OWNERSHIP_CONSTRUCTION_RIGHTS_OWNED, true);
// clang-format on
}
else if (
String::IEquals(gScenarioFileName, "Roaring Twenties - Schneider Cup.SC6")
|| String::IEquals(gScenarioFileName, "roaring twenties - schneider cup.sea"))
{
// clang-format off
FixLandOwnershipTilesWithOwnership(
{
{ 147, 132 },
{ 82, 110 }, { 83, 110 },
{ 120, 86 }, { 121, 86 },
{ 143, 130 }, { 144, 130 },
{ 98, 2 }, { 99, 2 }, { 100, 2 },
{ 65, 120 }, { 65, 121 }, { 65, 122 }, { 65, 123 },
{ 156, 139 }, { 156, 140 }, { 156, 141 }, { 157, 139 }, { 157, 140 }, { 157, 141 },
{ 105, 88 }, { 106, 86 }, { 106, 87 }, { 106, 88 }, { 107, 86 }, { 107, 87 }, { 107, 88 },
{ 148, 95 }, { 148, 96 }, { 148, 97 }, { 148, 98 }, { 148, 99 }, { 149, 97 }, { 149, 98 }, { 149, 99 }, { 150, 97 }, { 150, 98 }, { 150, 99 },
{ 148, 94 },
{ 84, 111 }, { 85, 111 }, { 85, 112 }, { 85, 113 }, { 85, 114 }, { 86, 111 }, { 86, 112 }, { 86, 113 }, { 86, 114 }, { 87, 111 }, { 87, 112 },
{ 87, 113 }, { 87, 114 }, { 88, 111 }, { 88, 112 }, { 88, 113 }, { 88, 114 }, { 88, 115 }, { 88, 116 }, { 88, 117 }, { 89, 111 }, { 89, 112 },
{ 89, 113 }, { 89, 114 }, { 89, 115 }, { 89, 116 }, { 89, 117 }, { 89, 118 }, { 89, 119 }, { 89, 120 }, { 89, 121 }, { 90, 113 }, { 90, 114 },
{ 90, 115 }, { 90, 116 }, { 90, 117 }, { 90, 118 }, { 90, 119 }, { 90, 120 }, { 90, 121 }, { 91, 115 }, { 91, 116 }, { 91, 117 }, { 91, 118 },
{ 91, 119 }, { 91, 120 }, { 91, 121 }, { 92, 115 }, { 92, 118 }, { 92, 119 }, { 92, 120 }, { 92, 121 },
},
OWNERSHIP_CONSTRUCTION_RIGHTS_AVAILABLE, true);
FixLandOwnershipTilesWithOwnership(
{
{ 45, 151 },
{ 55, 137 },
},
OWNERSHIP_AVAILABLE, true);
// clang-format on
}
else if (String::Equals(_s6.ScenarioFilename, "Mythological - Cradle of Civilization.SC6"))
{
// clang-format off
FixLandOwnershipTilesWithOwnership(
{
{ 103, 24 },
{ 104, 25 },
{ 116, 42 }, { 116, 43 }, { 116, 44 }, { 116, 45 }, { 116, 46 }, { 117, 41 }, { 117, 42 }, { 117, 43 }, { 117, 44 }, { 117, 45 }, { 117, 46 }
},
OWNERSHIP_AVAILABLE, true);
FixLandOwnershipTilesWithOwnership(
{
{ 86, 66 }, { 86, 67 }, { 86, 68 }, { 86, 69 }, { 86, 70 }, { 86, 71 }, { 87, 65 }, { 87, 66 }, { 87, 67 }, { 87, 68 }, { 87, 69 },
{ 87, 70 }, { 87, 71 }, { 87, 72 }, { 88, 65 }, { 88, 66 }, { 88, 67 }, { 88, 68 }, { 88, 69 }, { 88, 70 }, { 88, 71 }, { 88, 72 },
{ 88, 73 }, { 88, 74 }, { 88, 75 }, { 89, 65 }, { 89, 66 }, { 89, 67 }, { 89, 68 }, { 89, 69 }, { 89, 70 }, { 89, 71 }, { 89, 72 },
{ 89, 73 }, { 89, 74 }, { 89, 75 }, { 89, 76 }, { 90, 64 }, { 90, 65 }, { 90, 66 }, { 90, 67 }, { 90, 68 }, { 90, 69 }, { 90, 70 },
{ 90, 71 }, { 90, 72 }, { 90, 73 }, { 90, 74 }, { 90, 75 }, { 90, 76 }, { 90, 77 }, { 91, 67 }, { 91, 68 },
},
OWNERSHIP_OWNED);
// clang-format on
}
else if (
String::IEquals(gScenarioFileName, "Prehistoric - Stone Age.SC6")
|| String::IEquals(gScenarioFileName, "prehistoric - stone age.sea"))
{
// clang-format off
FixLandOwnershipTilesWithOwnership(
{
{ 58, 77 },
{ 62, 81 }, { 63, 81 }, { 64, 81 },
{ 59, 36 }, { 60, 36 }, { 61, 36 }, { 60, 37 }, { 61, 37 },
{ 73, 78 }, { 73, 79 }, { 73, 80 }, { 73, 81 }, { 73, 82 }, { 74, 79 }, { 74, 80 }, { 74, 81 }, { 74, 82 }, { 74, 83 },
{ 75, 79 }, { 75, 80 }, { 75, 81 }, { 75, 82 }, { 75, 83 }, { 76, 79 }, { 76, 80 }, { 76, 81 }, { 76, 82 }, { 76, 83 },
{ 77, 79 }, { 77, 80 }, { 77, 81 }, { 77, 82 }, { 78, 79 }, { 79, 79 }, { 80, 79 }, { 73, 77 },
},
OWNERSHIP_AVAILABLE, true);
// clang-format on
}
else if (String::Equals(_s6.ScenarioFilename, "Rock 'n' Roll - Rock 'n' Roll.SC6"))
{
// clang-format off
FixLandOwnershipTilesWithOwnership(
{
{ 13, 95 },
{ 80, 31 },
{ 56, 105 },
},
OWNERSHIP_AVAILABLE, true);
// clang-format on
}
}
void FixWater() const
{
if (!_isScenario)
{
return;
}
if (String::IEquals(_s6.ScenarioFilename, "Infernal Views.SC6")
|| String::IEquals(_s6.ScenarioFilename, "infernal views.sea"))
{
auto surfaceElement = MapGetSurfaceElementAt(TileCoordsXY{ 45, 62 });
surfaceElement->SetWaterHeight(96);
}
else if (
Fix #17774: gaps and errors in park boundaries and construction rights for RCT1 and RCT2 scenarios (#19657) * Update S6Importer.cpp * clang format error. Added changelog entry. * Update S6Importer.cpp * Added fixes for RCT1 scenarios The issues in Katie's Dreamland, Utopia Park, Urban Park, Pleasure Island, and Fort Anachronism listed in issue #17774 have been now dealt with. * Added land for Cradle's underwater path. * Update changelog.txt * Updated changelog. * specify text for path fix in Cradle * Update S6Importer.cpp * More missing tiles in Coastal Reclaim & Salvage * Update S6Importer.cpp * Update S6Importer.cpp * missed tile in stone age * Classic compatibility Added edit compatibility for classic scenarios on rct2 maps. * Update changelog.txt * Update S6Importer.cpp * Update S6Importer.cpp * Update S6Importer.cpp * Fun At The Beach Fixed errant tiles in Fun at the Beach. * Update S6Importer.cpp * Update S6Importer.cpp * Extreme Heights Fix missing tiles along edge of Extreme Heights park boundary; should run to 1 tile from the edge of the map almost all the way around. * Final Set of Changes Did a quick run-through of all the maps looking for any possible missed spots. I did find a series of spots, some clearly meant to be owned, and others that I'm a bit less than sure about. For now, I've commented out the spots that I don't feel are strictly necessary to have included, while the remaining ones I feel are necessary. * Update S4Importer.cpp * add optional fixes un-commented the extra changes; they are now included. * Update changelog.txt * fix clang format error * Update changelog.txt * Update S6Importer.cpp OOB underground path * Update S6Importer.cpp * Update S6Importer.cpp * above runaway plumber gaps * Update changelog.txt
2023-11-17 12:23:05 +01:00
String::Equals(_s6.ScenarioFilename, "Six Flags Holland.SC6", true)
|| String::Equals(_s6.ScenarioFilename, "six flags holland.sea", true))
{
auto surfaceElement = MapGetSurfaceElementAt(TileCoordsXY{ 126, 73 });
surfaceElement->SetWaterHeight(96);
}
}
void FixAyersRockScenario() const
{
2023-01-22 20:16:41 +01:00
if (!_isScenario || !String::Equals(_s6.ScenarioFilename, "Australasia - Ayers Rock.SC6"))
return;
TileCoordsXY tilesToUncovered[] = {
{ 123, 59 }, { 123, 60 }, { 123, 61 }, { 118, 69 }, { 118, 70 }, { 118, 71 },
{ 118, 72 }, { 118, 73 }, { 112, 79 }, { 112, 80 }, { 112, 81 }, { 112, 82 },
};
for (const auto& tile : tilesToUncovered)
{
auto* tileElement = MapGetFirstElementAt(tile);
if (tileElement == nullptr)
continue;
do
{
if (tileElement->GetType() != TileElementType::Track)
continue;
auto* trackElement = tileElement->AsTrack();
if (trackElement->GetTrackType() != TrackElemType::FlatCovered)
continue;
trackElement->SetTrackType(TrackElemType::Flat);
} while (!(tileElement++)->IsLastForTile());
}
TileCoordsXY tilesToCovered[] = {
{ 123, 83 },
{ 123, 84 },
{ 123, 85 },
{ 123, 86 },
};
for (const auto& tile : tilesToCovered)
{
auto* tileElement = MapGetFirstElementAt(tile);
if (tileElement == nullptr)
continue;
do
{
if (tileElement->GetType() != TileElementType::Track)
continue;
auto* trackElement = tileElement->AsTrack();
if (trackElement->GetTrackType() != TrackElemType::Flat)
continue;
trackElement->SetTrackType(TrackElemType::FlatCovered);
} while (!(tileElement++)->IsLastForTile());
}
}
void ImportRides()
{
for (uint8_t index = 0; index < Limits::MaxRidesInPark; index++)
{
2023-01-22 20:16:41 +01:00
auto src = &_s6.Rides[index];
if (src->Type != RIDE_TYPE_NULL)
{
2022-01-19 15:54:57 +01:00
const auto rideId = RideId::FromUnderlying(index);
auto dst = RideAllocateAtIndex(rideId);
ImportRide(dst, src, rideId);
}
}
}
2017-01-17 13:51:02 +01:00
/**
* This code is needed to detect hacks where a tracked ride has been made invisible
* by setting its ride type to a flat ride.
*
* The function should classify rides as follows:
* 1. If the ride type is tracked and its vehicles also belong on tracks, it should be classified as tracked.
* 2. If the ride type is a flat ride, but its vehicles belong on tracks,
* it should be classified as tracked (Crooked House mod).
* 3. If the ride type is tracked and its vehicles belong to a flat ride, it should be classified as tracked.
* 4. If the ride type is a flat ride and its vehicles also belong to a flat ride, it should be classified as a flat
* ride.
*/
void DetermineFlatRideStatus()
{
for (uint8_t index = 0; index < Limits::MaxRidesInPark; index++)
{
2023-01-22 20:16:41 +01:00
auto src = &_s6.Rides[index];
if (src->Type == RIDE_TYPE_NULL)
continue;
2023-01-22 20:16:41 +01:00
auto subtype = RCTEntryIndexToOpenRCT2EntryIndex(src->Subtype);
auto* rideEntry = GetRideEntryByIndex(subtype);
// If the ride is tracked, we dont need to check the vehicle any more.
2023-01-22 20:16:41 +01:00
if (!GetRideTypeDescriptor(src->Type).HasFlag(RIDE_TYPE_FLAG_FLAT_RIDE))
{
_isFlatRide[index] = false;
continue;
}
// We have established the ride type is a flat ride, which means the vehicle now determines whether it is a
// true flat ride (scenario 4) or a tracked ride with an invisibility hack (scenario 2).
2023-01-22 20:16:41 +01:00
ObjectEntryIndex originalRideType = src->Type;
if (rideEntry != nullptr)
{
originalRideType = rideEntry->GetFirstNonNullRideType();
}
const auto isFlatRide = GetRideTypeDescriptor(originalRideType).HasFlag(RIDE_TYPE_FLAG_FLAT_RIDE);
_isFlatRide.set(static_cast<size_t>(index), isFlatRide);
}
}
bool IsFlatRide(const uint8_t rct12RideIndex)
{
if (rct12RideIndex == RCT12_RIDE_ID_NULL)
return false;
return _isFlatRide[rct12RideIndex];
}
2022-01-19 14:17:11 +01:00
void ImportRide(::Ride* dst, const RCT2::Ride* src, const RideId rideIndex)
{
*dst = {};
dst->id = rideIndex;
2023-01-22 20:16:41 +01:00
ObjectEntryIndex rideType = src->Type;
auto subtype = RCTEntryIndexToOpenRCT2EntryIndex(src->Subtype);
if (RCT2RideTypeNeedsConversion(src->Type))
{
auto* rideEntry = GetRideEntryByIndex(subtype);
if (rideEntry != nullptr)
{
2023-01-22 20:16:41 +01:00
rideType = RCT2RideTypeToOpenRCT2RideType(src->Type, *rideEntry);
}
}
if (rideType >= RIDE_TYPE_COUNT)
{
LOG_ERROR("Invalid ride type for a ride in this save.");
throw UnsupportedRideTypeException(rideType);
}
dst->type = rideType;
dst->subtype = subtype;
2023-01-21 16:39:35 +01:00
// Pad002;
2023-01-22 20:16:41 +01:00
dst->mode = static_cast<RideMode>(src->Mode);
dst->colour_scheme_type = src->ColourSchemeType;
for (uint8_t i = 0; i < Limits::MaxVehicleColours; i++)
{
2023-01-22 20:16:41 +01:00
dst->vehicle_colours[i].Body = src->VehicleColours[i].BodyColour;
dst->vehicle_colours[i].Trim = src->VehicleColours[i].TrimColour;
}
2023-01-21 16:39:35 +01:00
// Pad046;
2023-01-22 20:16:41 +01:00
dst->status = static_cast<RideStatus>(src->Status);
2023-01-22 20:16:41 +01:00
dst->default_name_number = src->NameArgumentsNumber;
if (IsUserStringID(src->Name))
2020-07-17 00:32:47 +02:00
{
2023-01-22 20:16:41 +01:00
dst->custom_name = GetUserString(src->Name);
}
else
{
2023-01-22 20:16:41 +01:00
dst->default_name_number = src->NameArgumentsNumber;
2020-07-17 00:32:47 +02:00
}
2023-01-22 20:16:41 +01:00
if (src->OverallView.IsNull())
{
dst->overall_view.SetNull();
}
else
{
2023-01-22 20:16:41 +01:00
auto tileLoc = TileCoordsXY(src->OverallView.x, src->OverallView.y);
dst->overall_view = tileLoc.ToCoordsXY();
}
for (StationIndex::UnderlyingType i = 0; i < Limits::MaxStationsPerRide; i++)
{
StationIndex stationIndex = StationIndex::FromUnderlying(i);
auto& destStation = dst->GetStation(stationIndex);
2023-01-22 20:16:41 +01:00
if (src->StationStarts[i].IsNull())
{
destStation.Start.SetNull();
}
else
{
2023-01-22 20:16:41 +01:00
auto tileStartLoc = TileCoordsXY(src->StationStarts[i].x, src->StationStarts[i].y);
destStation.Start = tileStartLoc.ToCoordsXY();
}
2023-01-22 20:16:41 +01:00
destStation.Height = src->StationHeights[i];
destStation.Length = src->StationLength[i];
destStation.Depart = src->StationDepart[i];
destStation.TrainAtStation = src->TrainAtStation[i];
// Direction is fixed later.
2023-01-22 20:16:41 +01:00
if (src->Entrances[i].IsNull())
destStation.Entrance.SetNull();
else
2023-01-22 20:16:41 +01:00
destStation.Entrance = { src->Entrances[i].x, src->Entrances[i].y, src->StationHeights[i], 0 };
2023-01-22 20:16:41 +01:00
if (src->Exits[i].IsNull())
destStation.Exit.SetNull();
else
2023-01-22 20:16:41 +01:00
destStation.Exit = { src->Exits[i].x, src->Exits[i].y, src->StationHeights[i], 0 };
2019-07-21 03:22:03 +02:00
2023-01-22 20:16:41 +01:00
destStation.LastPeepInQueue = EntityId::FromUnderlying(src->LastPeepInQueue[i]);
2023-01-22 20:16:41 +01:00
destStation.SegmentLength = src->Length[i];
destStation.SegmentTime = src->Time[i];
2023-01-22 20:16:41 +01:00
destStation.QueueTime = src->QueueTime[i];
2023-01-22 20:16:41 +01:00
destStation.QueueLength = src->QueueLength[i];
}
// All other values take 0 as their default. Since they're already memset to that, no need to do it again.
for (int32_t i = Limits::MaxStationsPerRide; i < OpenRCT2::Limits::MaxStationsPerRide; i++)
{
StationIndex stationIndex = StationIndex::FromUnderlying(i);
auto& destStation = dst->GetStation(stationIndex);
destStation.Start.SetNull();
2024-03-03 16:53:44 +01:00
destStation.TrainAtStation = RideStation::kNoTrain;
destStation.Entrance.SetNull();
destStation.Exit.SetNull();
destStation.LastPeepInQueue = EntityId::GetNull();
}
for (int32_t i = 0; i < Limits::MaxTrainsPerRide; i++)
{
2023-01-22 20:16:41 +01:00
dst->vehicles[i] = EntityId::FromUnderlying(src->Vehicles[i]);
}
for (int32_t i = Limits::MaxTrainsPerRide - 1; i <= OpenRCT2::Limits::MaxTrainsPerRide; i++)
{
dst->vehicles[i] = EntityId::GetNull();
}
2023-01-22 20:16:41 +01:00
dst->depart_flags = src->DepartFlags;
2023-01-22 20:16:41 +01:00
dst->num_stations = src->NumStations;
dst->NumTrains = src->NumTrains;
2023-01-22 20:16:41 +01:00
dst->num_cars_per_train = src->NumCarsPerTrain;
dst->ProposedNumTrains = src->ProposedNumTrains;
2023-01-22 20:16:41 +01:00
dst->proposed_num_cars_per_train = src->ProposedNumCarsPerTrain;
dst->max_trains = src->MaxTrains;
dst->MinCarsPerTrain = src->GetMinCarsPerTrain();
dst->MaxCarsPerTrain = src->GetMaxCarsPerTrain();
2023-01-22 20:16:41 +01:00
dst->min_waiting_time = src->MinWaitingTime;
dst->max_waiting_time = src->MaxWaitingTime;
2022-02-21 03:20:06 +01:00
// Includes time_limit, NumLaps, launch_speed, speed, rotations
2023-01-22 20:16:41 +01:00
dst->operation_option = src->OperationOption;
2023-01-22 20:16:41 +01:00
dst->boat_hire_return_direction = src->BoatHireReturnDirection;
dst->boat_hire_return_position = { src->BoatHireReturnPosition.x, src->BoatHireReturnPosition.y };
2023-01-22 20:16:41 +01:00
dst->special_track_elements = src->SpecialTrackElements;
2023-01-21 16:39:35 +01:00
// Pad0D6[2];
2023-01-22 20:16:41 +01:00
dst->max_speed = src->MaxSpeed;
dst->average_speed = src->AverageSpeed;
dst->current_test_segment = src->CurrentTestSegment;
dst->average_speed_test_timeout = src->AverageSpeedTestTimeout;
2023-01-21 16:39:35 +01:00
// Pad0E2[0x2];
2023-01-22 20:16:41 +01:00
dst->max_positive_vertical_g = src->MaxPositiveVerticalG;
dst->max_negative_vertical_g = src->MaxNegativeVerticalG;
dst->max_lateral_g = src->MaxLateralG;
dst->previous_vertical_g = src->PreviousVerticalG;
dst->previous_lateral_g = src->PreviousLateralG;
2023-01-21 16:39:35 +01:00
// Pad106[0x2];
2023-01-22 20:16:41 +01:00
dst->testing_flags = src->TestingFlags;
2023-01-22 20:16:41 +01:00
if (src->CurTestTrackLocation.IsNull())
{
dst->CurTestTrackLocation.SetNull();
}
else
{
2023-01-22 20:16:41 +01:00
dst->CurTestTrackLocation = { src->CurTestTrackLocation.x, src->CurTestTrackLocation.y, src->CurTestTrackZ };
}
2023-01-22 20:16:41 +01:00
dst->turn_count_default = src->TurnCountDefault;
dst->turn_count_banked = src->TurnCountBanked;
dst->turn_count_sloped = src->TurnCountSloped;
if (dst->type == RIDE_TYPE_MINI_GOLF)
2023-01-22 20:16:41 +01:00
dst->holes = src->Inversions & 0x1F;
else
2023-01-22 20:16:41 +01:00
dst->inversions = src->Inversions & 0x1F;
dst->sheltered_eighths = src->Inversions >> 5;
dst->drops = src->Drops;
dst->start_drop_height = src->StartDropHeight;
dst->highest_drop_height = src->HighestDropHeight;
dst->sheltered_length = src->ShelteredLength;
dst->var_11C = src->Var11C;
dst->num_sheltered_sections = src->NumShelteredSections;
dst->cur_num_customers = src->CurNumCustomers;
dst->num_customers_timeout = src->NumCustomersTimeout;
for (uint8_t i = 0; i < Limits::CustomerHistorySize; i++)
{
2023-01-22 20:16:41 +01:00
dst->num_customers[i] = src->NumCustomers[i];
}
2023-01-22 20:16:41 +01:00
dst->price[0] = src->Price;
for (uint8_t i = 0; i < 2; i++)
{
2023-01-22 20:16:41 +01:00
dst->ChairliftBullwheelLocation[i] = { src->ChairliftBullwheelLocation[i].x,
src->ChairliftBullwheelLocation[i].y, src->ChairliftBullwheelZ[i] };
}
2023-01-22 20:16:41 +01:00
dst->ratings = src->Ratings;
dst->value = ToMoney64(src->Value);
2023-01-22 20:16:41 +01:00
dst->chairlift_bullwheel_rotation = src->ChairliftBullwheelRotation;
2023-01-22 20:16:41 +01:00
dst->satisfaction = src->Satisfaction;
dst->satisfaction_time_out = src->SatisfactionTimeOut;
dst->satisfaction_next = src->SatisfactionNext;
2023-01-22 20:16:41 +01:00
dst->window_invalidate_flags = src->WindowInvalidateFlags;
2023-01-21 16:39:35 +01:00
// Pad14E[0x02];
2023-01-22 20:16:41 +01:00
dst->total_customers = src->TotalCustomers;
dst->total_profit = ToMoney64(src->TotalProfit);
dst->popularity = src->Popularity;
dst->popularity_time_out = src->PopularityTimeOut;
dst->popularity_next = src->PopularityNext;
ImportNumRiders(dst, rideIndex);
2023-01-22 20:16:41 +01:00
dst->music_tune_id = src->MusicTuneId;
dst->slide_in_use = src->SlideInUse;
// Includes maze_tiles
2023-01-22 20:16:41 +01:00
dst->slide_peep = EntityId::FromUnderlying(src->SlidePeep);
2023-01-21 16:39:35 +01:00
// Pad160[0xE];
2023-01-22 20:16:41 +01:00
dst->slide_peep_t_shirt_colour = src->SlidePeepTShirtColour;
2023-01-21 16:39:35 +01:00
// Pad16F[0x7];
2023-01-22 20:16:41 +01:00
dst->spiral_slide_progress = src->SpiralSlideProgress;
2023-01-21 16:39:35 +01:00
// Pad177[0x9];
2023-01-22 20:16:41 +01:00
dst->build_date = static_cast<int32_t>(src->BuildDate);
dst->upkeep_cost = ToMoney64(src->UpkeepCost);
2023-01-22 20:16:41 +01:00
dst->race_winner = EntityId::FromUnderlying(src->RaceWinner);
2023-01-21 16:39:35 +01:00
// Pad186[0x02];
2023-01-22 20:16:41 +01:00
dst->music_position = src->MusicPosition;
2023-01-22 20:16:41 +01:00
dst->breakdown_reason_pending = src->BreakdownReasonPending;
dst->mechanic_status = src->MechanicStatus;
dst->mechanic = EntityId::FromUnderlying(src->Mechanic);
dst->inspection_station = StationIndex::FromUnderlying(src->InspectionStation);
dst->broken_vehicle = src->BrokenVehicle;
dst->broken_car = src->BrokenCar;
dst->breakdown_reason = src->BreakdownReason;
2023-01-22 20:16:41 +01:00
dst->price[1] = src->PriceSecondary;
2023-01-22 20:16:41 +01:00
dst->reliability = src->Reliability;
dst->unreliability_factor = src->UnreliabilityFactor;
dst->downtime = src->Downtime;
dst->inspection_interval = src->InspectionInterval;
dst->last_inspection = src->LastInspection;
for (uint8_t i = 0; i < Limits::DowntimeHistorySize; i++)
{
2023-01-22 20:16:41 +01:00
dst->downtime_history[i] = src->DowntimeHistory[i];
}
2023-01-22 20:16:41 +01:00
dst->no_primary_items_sold = src->NoPrimaryItemsSold;
dst->no_secondary_items_sold = src->NoSecondaryItemsSold;
2023-01-22 20:16:41 +01:00
dst->breakdown_sound_modifier = src->BreakdownSoundModifier;
dst->not_fixed_timeout = src->NotFixedTimeout;
dst->last_crash_type = src->LastCrashType;
dst->connected_message_throttle = src->ConnectedMessageThrottle;
2023-01-22 20:16:41 +01:00
dst->income_per_hour = ToMoney64(src->IncomePerHour);
dst->profit = ToMoney64(src->Profit);
for (uint8_t i = 0; i < Limits::NumColourSchemes; i++)
{
2023-01-22 20:16:41 +01:00
dst->track_colour[i].main = src->TrackColourMain[i];
dst->track_colour[i].additional = src->TrackColourAdditional[i];
dst->track_colour[i].supports = src->TrackColourSupports[i];
}
// This stall was not colourable in RCT2.
if (dst->type == RIDE_TYPE_FOOD_STALL)
{
auto object = ObjectEntryGetObject(ObjectType::Ride, dst->subtype);
if (object != nullptr && object->GetIdentifier() == "rct2.ride.icecr1")
{
dst->track_colour[0].main = COLOUR_LIGHT_BLUE;
}
}
auto musicStyle = OBJECT_ENTRY_INDEX_NULL;
if (GetRideTypeDescriptor(dst->type).HasFlag(RIDE_TYPE_FLAG_ALLOW_MUSIC))
{
2023-01-22 20:16:41 +01:00
musicStyle = src->Music;
}
dst->music = musicStyle;
// In SV7, "plain" entrances are invisible.
auto entranceStyle = OBJECT_ENTRY_INDEX_NULL;
if (!_isSV7 && GetRideTypeDescriptor(dst->type).HasFlag(RIDE_TYPE_FLAG_HAS_ENTRANCE_EXIT))
{
2023-01-22 20:16:41 +01:00
entranceStyle = src->EntranceStyle;
}
dst->entrance_style = entranceStyle;
2023-01-22 20:16:41 +01:00
dst->vehicle_change_timeout = src->VehicleChangeTimeout;
dst->num_block_brakes = src->NumBlockBrakes;
dst->lift_hill_speed = src->LiftHillSpeed;
dst->guests_favourite = src->GuestsFavourite;
dst->lifecycle_flags = src->LifecycleFlags;
for (uint8_t i = 0; i < Limits::MaxTrainsPerRide; i++)
{
2023-01-22 20:16:41 +01:00
dst->vehicle_colours[i].Tertiary = src->VehicleColoursExtended[i];
}
2023-01-22 20:16:41 +01:00
dst->total_air_time = src->TotalAirTime;
dst->current_test_station = StationIndex::FromUnderlying(src->CurrentTestStation);
dst->num_circuits = src->NumCircuits;
dst->CableLiftLoc = { src->CableLiftX, src->CableLiftY, src->CableLiftZ * COORDS_Z_STEP };
2023-01-21 16:39:35 +01:00
// Pad1FD;
2023-01-22 20:16:41 +01:00
dst->cable_lift = EntityId::FromUnderlying(src->CableLift);
2023-01-21 16:39:35 +01:00
// Pad208[0x58];
}
void ImportRideRatingsCalcData()
{
2023-01-22 20:16:41 +01:00
const auto& src = _s6.RideRatingsCalcData;
// S6 has only one state, ensure we reset all states before reading the first one.
RideRatingResetUpdateStates();
auto& rideRatingStates = GetGameState().RideRatingUpdateStates;
auto& dst = rideRatingStates[0];
dst = {};
2023-01-22 20:16:41 +01:00
dst.Proximity = { src.ProximityX, src.ProximityY, src.ProximityZ };
dst.ProximityStart = { src.ProximityStartX, src.ProximityStartY, src.ProximityStartZ };
dst.CurrentRide = RCT12RideIdToOpenRCT2RideId(src.CurrentRide);
dst.State = src.State;
if (src.CurrentRide < Limits::MaxRidesInPark && _s6.Rides[src.CurrentRide].Type < std::size(RideTypeDescriptors))
dst.ProximityTrackType = RCT2TrackTypeToOpenRCT2(
2023-01-22 20:16:41 +01:00
src.ProximityTrackType, _s6.Rides[src.CurrentRide].Type, IsFlatRide(src.CurrentRide));
else
dst.ProximityTrackType = 0xFF;
2023-01-22 20:16:41 +01:00
dst.ProximityBaseHeight = src.ProximityBaseHeight;
dst.ProximityTotal = src.ProximityTotal;
for (size_t i = 0; i < std::size(src.ProximityScores); i++)
{
2023-01-22 20:16:41 +01:00
dst.ProximityScores[i] = src.ProximityScores[i];
}
2023-01-22 20:16:41 +01:00
dst.AmountOfBrakes = src.NumBrakes;
dst.AmountOfReversers = src.NumReversers;
dst.StationFlags = src.StationFlags;
}
void ImportRideMeasurements()
{
2023-01-22 20:16:41 +01:00
for (const auto& src : _s6.RideMeasurements)
{
2023-01-22 20:16:41 +01:00
if (src.RideIndex != RCT12_RIDE_ID_NULL)
{
2023-01-22 20:16:41 +01:00
const auto rideId = RideId::FromUnderlying(src.RideIndex);
auto ride = GetRide(rideId);
if (ride != nullptr)
{
ride->measurement = std::make_unique<RideMeasurement>();
ImportRideMeasurement(*ride->measurement, src);
}
}
}
}
void ImportRideMeasurement(RideMeasurement& dst, const RCT12RideMeasurement& src)
2021-09-01 10:16:44 +02:00
{
2023-01-22 20:16:41 +01:00
dst.flags = src.Flags;
dst.last_use_tick = src.LastUseTick;
dst.num_items = src.NumItems;
dst.current_item = src.CurrentItem;
dst.vehicle_index = src.VehicleIndex;
dst.current_station = StationIndex::FromUnderlying(src.CurrentStation);
for (size_t i = 0; i < std::size(src.Velocity); i++)
{
dst.velocity[i] = src.Velocity[i];
dst.altitude[i] = src.Altitude[i];
dst.vertical[i] = src.Vertical[i];
dst.lateral[i] = src.Lateral[i];
}
}
void ImportResearchList(GameState_t& gameState)
2019-06-09 11:55:41 +02:00
{
bool invented = true;
2023-01-22 20:16:41 +01:00
for (const auto& researchItem : _s6.ResearchItems)
2019-06-09 11:55:41 +02:00
{
if (researchItem.IsInventedEndMarker())
{
invented = false;
continue;
}
if (researchItem.IsUninventedEndMarker() || researchItem.IsRandomEndMarker())
{
break;
}
if (invented)
2024-01-29 21:33:39 +01:00
gameState.ResearchItemsInvented.emplace_back(researchItem.ToResearchItem());
else
2024-01-29 21:33:39 +01:00
gameState.ResearchItemsUninvented.emplace_back(researchItem.ToResearchItem());
2019-06-09 11:55:41 +02:00
}
}
void ImportBanner(Banner* dst, const RCT12Banner* src)
2019-06-09 11:55:41 +02:00
{
auto id = dst->id;
2019-06-09 11:55:41 +02:00
*dst = {};
dst->id = id;
2023-01-22 20:16:41 +01:00
dst->type = RCTEntryIndexToOpenRCT2EntryIndex(src->Type);
dst->flags = src->Flags;
2023-01-22 20:16:41 +01:00
if (!(src->Flags & BANNER_FLAG_LINKED_TO_RIDE) && IsUserStringID(src->StringID))
2019-06-16 23:32:31 +02:00
{
2023-01-22 20:16:41 +01:00
dst->text = GetUserString(src->StringID);
2019-06-16 23:32:31 +02:00
}
2023-01-22 20:16:41 +01:00
if (src->Flags & BANNER_FLAG_LINKED_TO_RIDE)
2019-06-16 23:32:31 +02:00
{
2023-01-22 20:16:41 +01:00
dst->ride_index = RCT12RideIdToOpenRCT2RideId(src->RideIndex);
2019-06-16 23:32:31 +02:00
}
else
{
2023-01-22 20:16:41 +01:00
dst->colour = src->Colour;
}
2019-07-21 18:40:52 +02:00
2023-01-22 20:16:41 +01:00
dst->text_colour = src->TextColour;
dst->position.x = src->x;
dst->position.y = src->y;
2019-07-21 18:40:52 +02:00
}
2024-03-26 15:08:17 +01:00
void Initialise(GameState_t& gameState)
{
2024-03-26 15:08:17 +01:00
gameStateInitAll(gameState, { _s6.MapSize, _s6.MapSize });
}
/**
* Imports guest entry points.
* Includes fixes for incorrectly set guest entry points in some scenarios.
*/
void ImportPeepSpawns()
{
// Many WW and TT have scenario_filename fields containing an incorrect filename. Check for both this filename
// and the corrected filename.
// In this park, peep_spawns[0] is incorrect, and peep_spawns[1] is correct.
2023-01-22 20:16:41 +01:00
if (String::Equals(_s6.ScenarioFilename, "WW South America - Rio Carnival.SC6")
|| String::Equals(_s6.ScenarioFilename, "South America - Rio Carnival.SC6"))
{
2023-01-22 20:16:41 +01:00
_s6.PeepSpawns[0] = { 2160, 3167, 6, 1 };
_s6.PeepSpawns[1].x = RCT12_PEEP_SPAWN_UNDEFINED;
}
// In this park, peep_spawns[0] is correct. Just clear the other.
else if (
2023-01-22 20:16:41 +01:00
String::Equals(_s6.ScenarioFilename, "Great Wall of China Tourism Enhancement.SC6")
|| String::Equals(_s6.ScenarioFilename, "Asia - Great Wall of China Tourism Enhancement.SC6"))
{
2023-01-22 20:16:41 +01:00
_s6.PeepSpawns[1].x = RCT12_PEEP_SPAWN_UNDEFINED;
}
// Amity Airfield has peeps entering from the corner of the tile, instead of the middle.
2023-01-22 20:16:41 +01:00
else if (String::Equals(_s6.ScenarioFilename, "Amity Airfield.SC6"))
{
2023-01-22 20:16:41 +01:00
_s6.PeepSpawns[0].y = 1296;
}
// #9926: Africa - Oasis has peeps spawning on the edge underground near the entrance
2023-01-22 20:16:41 +01:00
else if (String::Equals(_s6.ScenarioFilename, "Africa - Oasis.SC6"))
{
2023-01-22 20:16:41 +01:00
_s6.PeepSpawns[0].y = 2128;
_s6.PeepSpawns[0].z = 7;
}
auto& gameState = GetGameState();
gameState.PeepSpawns.clear();
for (size_t i = 0; i < Limits::MaxPeepSpawns; i++)
{
2023-01-22 20:16:41 +01:00
if (_s6.PeepSpawns[i].x != RCT12_PEEP_SPAWN_UNDEFINED)
{
2023-01-22 20:16:41 +01:00
PeepSpawn spawn = { _s6.PeepSpawns[i].x, _s6.PeepSpawns[i].y, _s6.PeepSpawns[i].z * 16,
_s6.PeepSpawns[i].direction };
gameState.PeepSpawns.push_back(spawn);
}
}
}
2022-01-19 14:17:11 +01:00
void ImportNumRiders(::Ride* dst, const RideId rideIndex)
{
// The number of riders might have overflown or underflown. Re-calculate the value.
uint16_t numRiders = 0;
for (int32_t i = 0; i < GetMaxEntities(); i++)
{
2023-01-22 20:16:41 +01:00
const auto& entity = _s6.Entities[i];
if (entity.Unknown.EntityIdentifier == RCT12EntityIdentifier::Peep)
{
2023-01-22 20:16:41 +01:00
if (entity.Peep.CurrentRide == static_cast<RCT12RideId>(rideIndex.ToUnderlying())
&& (static_cast<PeepState>(entity.Peep.State) == PeepState::OnRide
|| static_cast<PeepState>(entity.Peep.State) == PeepState::EnteringRide))
{
numRiders++;
}
}
}
dst->num_riders = numRiders;
}
void ImportTileElements()
{
// Build tile pointer cache (needed to get the first element at a certain location)
auto tilePointerIndex = TilePointerIndex<RCT12TileElement>(
2023-01-22 20:16:41 +01:00
Limits::MaxMapSize, _s6.TileElements, std::size(_s6.TileElements));
std::vector<TileElement> tileElements;
bool nextElementInvisible = false;
bool restOfTileInvisible = false;
2023-01-22 20:16:41 +01:00
const auto maxSize = std::min(Limits::MaxMapSize, _s6.MapSize);
for (TileCoordsXY coords = { 0, 0 }; coords.y < kMaximumMapSizeTechnical; coords.y++)
{
for (coords.x = 0; coords.x < kMaximumMapSizeTechnical; coords.x++)
2021-01-15 16:23:28 +01:00
{
nextElementInvisible = false;
restOfTileInvisible = false;
auto tileAdded = false;
if (coords.x < maxSize && coords.y < maxSize)
{
const auto* srcElement = tilePointerIndex.GetFirstElementAt(coords);
if (srcElement != nullptr)
{
do
{
if (srcElement->BaseHeight == RCT12::Limits::MaxElementHeight)
{
continue;
}
2021-12-18 19:43:30 +01:00
auto tileElementType = srcElement->GetType();
if (tileElementType == RCT12TileElementType::Corrupt)
{
// One property of corrupt elements was to hide tops of tower tracks, and to avoid the next
// element from being hidden, multiple consecutive corrupt elements were sometimes used.
// This would essentially toggle the flag, so we inverse nextElementInvisible here instead
// of always setting it to true.
nextElementInvisible = !nextElementInvisible;
continue;
}
if (tileElementType == RCT12TileElementType::EightCarsCorrupt14
|| tileElementType == RCT12TileElementType::EightCarsCorrupt15)
{
restOfTileInvisible = true;
continue;
}
auto& dstElement = tileElements.emplace_back();
ImportTileElement(&dstElement, srcElement, nextElementInvisible || restOfTileInvisible);
nextElementInvisible = false;
tileAdded = true;
} while (!(srcElement++)->IsLastForTile());
}
}
2021-01-15 16:23:28 +01:00
if (!tileAdded)
{
// Add a default surface element, we always need at least one element per tile
auto& dstElement = tileElements.emplace_back();
2021-12-11 00:39:39 +01:00
dstElement.ClearAs(TileElementType::Surface);
dstElement.SetLastForTile(true);
}
2021-01-15 16:23:28 +01:00
// Set last element flag in case the original last element was never added
if (tileElements.size() > 0)
{
tileElements.back().SetLastForTile(true);
}
}
}
SetTileElements(std::move(tileElements));
}
2019-02-18 18:20:01 +01:00
void ImportTileElement(TileElement* dst, const RCT12TileElement* src, bool invisible)
{
2021-12-18 19:43:30 +01:00
const auto rct12Type = src->GetType();
dst->ClearAs(ToOpenRCT2TileElementType(rct12Type));
dst->SetDirection(src->GetDirection());
dst->SetBaseZ(src->BaseHeight * COORDS_Z_STEP);
dst->SetClearanceZ(src->ClearanceHeight * COORDS_Z_STEP);
// All saved in "flags"
dst->SetOccupiedQuadrants(src->GetOccupiedQuadrants());
dst->SetGhost(src->IsGhost());
dst->SetLastForTile(src->IsLastForTile());
dst->SetInvisible(invisible);
2021-12-18 19:43:30 +01:00
switch (rct12Type)
{
case RCT12TileElementType::Surface:
{
auto dst2 = dst->AsSurface();
auto src2 = src->AsSurface();
dst2->SetSlope(src2->GetSlope());
dst2->SetSurfaceObjectIndex(src2->GetSurfaceStyle());
dst2->SetEdgeObjectIndex(src2->GetEdgeStyle());
dst2->SetGrassLength(src2->GetGrassLength());
dst2->SetOwnership(src2->GetOwnership());
dst2->SetParkFences(src2->GetParkFences());
dst2->SetWaterHeight(src2->GetWaterHeight());
dst2->SetHasTrackThatNeedsWater(src2->HasTrackThatNeedsWater());
break;
}
case RCT12TileElementType::Path:
{
auto dst2 = dst->AsPath();
auto src2 = src->AsPath();
auto pathEntryIndex = src2->GetEntryIndex();
auto surfaceEntry = src2->IsQueue() ? _pathToQueueSurfaceMap[pathEntryIndex]
: _pathToSurfaceMap[pathEntryIndex];
if (surfaceEntry == OBJECT_ENTRY_INDEX_NULL)
{
// Legacy footpath object
dst2->SetLegacyPathEntryIndex(pathEntryIndex);
}
else
{
// Surface / railing
dst2->SetSurfaceEntryIndex(surfaceEntry);
dst2->SetRailingsEntryIndex(_pathToRailingMap[pathEntryIndex]);
}
dst2->SetQueueBannerDirection(src2->GetQueueBannerDirection());
dst2->SetSloped(src2->IsSloped());
dst2->SetSlopeDirection(src2->GetSlopeDirection());
dst2->SetRideIndex(RCT12RideIdToOpenRCT2RideId(src2->GetRideIndex()));
dst2->SetStationIndex(StationIndex::FromUnderlying(src2->GetStationIndex()));
dst2->SetWide(src2->IsWide());
dst2->SetIsQueue(src2->IsQueue());
dst2->SetHasQueueBanner(src2->HasQueueBanner());
dst2->SetEdges(src2->GetEdges());
dst2->SetCorners(src2->GetCorners());
dst2->SetAddition(src2->GetAddition());
dst2->SetAdditionIsGhost(src2->AdditionIsGhost());
dst2->SetAdditionStatus(src2->GetAdditionStatus());
dst2->SetIsBroken(src2->IsBroken());
dst2->SetIsBlockedByVehicle(src2->IsBlockedByVehicle());
break;
}
case RCT12TileElementType::Track:
{
auto dst2 = dst->AsTrack();
auto src2 = src->AsTrack();
2023-01-22 20:16:41 +01:00
auto rideType = _s6.Rides[src2->GetRideIndex()].Type;
track_type_t trackType = static_cast<track_type_t>(src2->GetTrackType());
dst2->SetTrackType(RCT2TrackTypeToOpenRCT2(trackType, rideType, IsFlatRide(src2->GetRideIndex())));
dst2->SetRideType(rideType);
dst2->SetSequenceIndex(src2->GetSequenceIndex());
dst2->SetRideIndex(RCT12RideIdToOpenRCT2RideId(src2->GetRideIndex()));
dst2->SetColourScheme(src2->GetColourScheme());
dst2->SetHasChain(src2->HasChain());
dst2->SetHasCableLift(src2->HasCableLift());
dst2->SetInverted(src2->IsInverted());
dst2->SetStationIndex(StationIndex::FromUnderlying(src2->GetStationIndex()));
dst2->SetHasGreenLight(src2->HasGreenLight());
// Brakes import as closed to preserve legacy behaviour
dst2->SetBrakeClosed(src2->BlockBrakeClosed() || (trackType == TrackElemType::Brakes));
dst2->SetIsIndestructible(src2->IsIndestructible());
// Skipping IsHighlighted()
// Import block brakes to keep legacy behaviour
if (trackType == TrackElemType::BlockBrakes)
{
dst2->SetBrakeBoosterSpeed(kRCT2DefaultBlockBrakeSpeed);
}
else if (TrackTypeHasSpeedSetting(trackType))
{
dst2->SetBrakeBoosterSpeed(src2->GetBrakeBoosterSpeed());
}
else if (trackType == TrackElemType::OnRidePhoto)
{
dst2->SetPhotoTimeout(src2->GetPhotoTimeout());
}
2019-09-19 22:56:54 +02:00
// This has to be done last, since the maze entry shares fields with the colour and sequence fields.
2022-12-14 14:21:21 +01:00
const auto& rtd = GetRideTypeDescriptor(rideType);
if (rtd.HasFlag(RIDE_TYPE_FLAG_IS_MAZE))
{
dst2->SetMazeEntry(src2->GetMazeEntry());
}
else if (rideType == RIDE_TYPE_GHOST_TRAIN)
{
dst2->SetDoorAState(src2->GetDoorAState());
dst2->SetDoorBState(src2->GetDoorBState());
}
else
{
dst2->SetSeatRotation(src2->GetSeatRotation());
}
if (TrackTypeMustBeMadeInvisible(rideType, dst2->GetTrackType()))
{
dst->SetInvisible(true);
}
break;
2019-08-31 13:14:19 +02:00
}
case RCT12TileElementType::SmallScenery:
{
auto dst2 = dst->AsSmallScenery();
auto src2 = src->AsSmallScenery();
dst2->SetEntryIndex(src2->GetEntryIndex());
dst2->SetAge(src2->GetAge());
dst2->SetSceneryQuadrant(src2->GetSceneryQuadrant());
dst2->SetPrimaryColour(src2->GetPrimaryColour());
dst2->SetSecondaryColour(src2->GetSecondaryColour());
if (src2->NeedsSupports())
dst2->SetNeedsSupports();
break;
}
case RCT12TileElementType::Entrance:
{
auto dst2 = dst->AsEntrance();
auto src2 = src->AsEntrance();
dst2->SetEntranceType(src2->GetEntranceType());
dst2->SetRideIndex(RCT12RideIdToOpenRCT2RideId(src2->GetRideIndex()));
dst2->SetStationIndex(StationIndex::FromUnderlying(src2->GetStationIndex()));
dst2->SetSequenceIndex(src2->GetSequenceIndex());
if (src2->GetSequenceIndex() == 0)
{
auto pathEntryIndex = src2->GetPathType();
auto surfaceEntry = _pathToSurfaceMap[pathEntryIndex];
if (surfaceEntry == OBJECT_ENTRY_INDEX_NULL)
{
// Legacy footpath object
dst2->SetLegacyPathEntryIndex(pathEntryIndex);
}
else
{
// Surface
dst2->SetSurfaceEntryIndex(surfaceEntry);
}
}
else
{
dst2->SetSurfaceEntryIndex(OBJECT_ENTRY_INDEX_NULL);
}
break;
}
case RCT12TileElementType::Wall:
{
auto dst2 = dst->AsWall();
auto src2 = src->AsWall();
dst2->SetEntryIndex(src2->GetEntryIndex());
dst2->SetSlope(src2->GetSlope());
dst2->SetPrimaryColour(src2->GetPrimaryColour());
dst2->SetSecondaryColour(src2->GetSecondaryColour());
dst2->SetTertiaryColour(src2->GetTertiaryColour());
dst2->SetAnimationFrame(src2->GetAnimationFrame());
dst2->SetAcrossTrack(src2->IsAcrossTrack());
dst2->SetAnimationIsBackwards(src2->AnimationIsBackwards());
// Import banner information
2021-11-24 21:25:36 +01:00
dst2->SetBannerIndex(BannerIndex::GetNull());
auto entry = dst2->GetEntry();
if (entry != nullptr && entry->scrolling_mode != SCROLLING_MODE_NONE)
{
auto bannerIndex = src2->GetBannerIndex();
2023-01-22 20:16:41 +01:00
if (bannerIndex < std::size(_s6.Banners))
{
2023-01-22 20:16:41 +01:00
auto srcBanner = &_s6.Banners[bannerIndex];
2021-11-24 18:58:07 +01:00
auto dstBanner = GetOrCreateBanner(BannerIndex::FromUnderlying(bannerIndex));
if (dstBanner == nullptr)
{
2021-11-24 21:25:36 +01:00
dst2->SetBannerIndex(BannerIndex::GetNull());
}
else
{
ImportBanner(dstBanner, srcBanner);
2021-11-24 18:58:07 +01:00
dst2->SetBannerIndex(BannerIndex::FromUnderlying(src2->GetBannerIndex()));
}
}
}
break;
}
case RCT12TileElementType::LargeScenery:
{
auto dst2 = dst->AsLargeScenery();
auto src2 = src->AsLargeScenery();
dst2->SetEntryIndex(src2->GetEntryIndex());
dst2->SetSequenceIndex(src2->GetSequenceIndex());
dst2->SetPrimaryColour(src2->GetPrimaryColour());
dst2->SetSecondaryColour(src2->GetSecondaryColour());
// Import banner information
2021-11-24 21:25:36 +01:00
dst2->SetBannerIndex(BannerIndex::GetNull());
auto entry = dst2->GetEntry();
if (entry != nullptr && entry->scrolling_mode != SCROLLING_MODE_NONE)
{
auto bannerIndex = src2->GetBannerIndex();
2023-01-22 20:16:41 +01:00
if (bannerIndex < std::size(_s6.Banners))
{
2023-01-22 20:16:41 +01:00
auto srcBanner = &_s6.Banners[bannerIndex];
2021-11-24 18:58:07 +01:00
auto dstBanner = GetOrCreateBanner(BannerIndex::FromUnderlying(bannerIndex));
if (dstBanner == nullptr)
{
2021-11-24 21:25:36 +01:00
dst2->SetBannerIndex(BannerIndex::GetNull());
}
else
{
ImportBanner(dstBanner, srcBanner);
2021-11-24 18:58:07 +01:00
dst2->SetBannerIndex(BannerIndex::FromUnderlying(src2->GetBannerIndex()));
}
}
}
break;
}
case RCT12TileElementType::Banner:
{
auto dst2 = dst->AsBanner();
auto src2 = src->AsBanner();
dst2->SetPosition(src2->GetPosition());
dst2->SetAllowedEdges(src2->GetAllowedEdges());
auto bannerIndex = src2->GetIndex();
2023-01-22 20:16:41 +01:00
if (bannerIndex < std::size(_s6.Banners))
{
2023-01-22 20:16:41 +01:00
auto srcBanner = &_s6.Banners[bannerIndex];
2021-11-24 18:58:07 +01:00
auto dstBanner = GetOrCreateBanner(BannerIndex::FromUnderlying(bannerIndex));
if (dstBanner == nullptr)
{
2021-11-24 21:25:36 +01:00
dst2->SetIndex(BannerIndex::GetNull());
}
else
{
ImportBanner(dstBanner, srcBanner);
2021-11-24 18:58:07 +01:00
dst2->SetIndex(BannerIndex::FromUnderlying(bannerIndex));
}
}
else
{
2021-11-24 21:25:36 +01:00
dst2->SetIndex(BannerIndex::GetNull());
}
break;
}
default:
assert(false);
}
}
void ImportMarketingCampaigns()
{
for (size_t i = 0; i < ADVERTISING_CAMPAIGN_COUNT; i++)
{
2023-01-22 20:16:41 +01:00
if (_s6.CampaignWeeksLeft[i] & CAMPAIGN_ACTIVE_FLAG)
{
MarketingCampaign campaign{};
campaign.Type = static_cast<uint8_t>(i);
2023-01-22 20:16:41 +01:00
campaign.WeeksLeft = _s6.CampaignWeeksLeft[i] & ~(CAMPAIGN_ACTIVE_FLAG | CAMPAIGN_FIRST_WEEK_FLAG);
if ((_s6.CampaignWeeksLeft[i] & CAMPAIGN_FIRST_WEEK_FLAG) != 0)
{
campaign.Flags |= MarketingCampaignFlags::FIRST_WEEK;
}
if (campaign.Type == ADVERTISING_CAMPAIGN_RIDE_FREE || campaign.Type == ADVERTISING_CAMPAIGN_RIDE)
{
2023-01-22 20:16:41 +01:00
campaign.RideId = RCT12RideIdToOpenRCT2RideId(_s6.CampaignRideIndex[i]);
}
else if (campaign.Type == ADVERTISING_CAMPAIGN_FOOD_OR_DRINK_FREE)
{
2023-01-22 20:16:41 +01:00
campaign.ShopItemType = ShopItem(_s6.CampaignRideIndex[i]);
}
gMarketingCampaigns.push_back(campaign);
}
}
}
2019-02-18 18:20:01 +01:00
void ImportStaffPatrolArea(Staff* staffmember, uint8_t staffId)
{
// First check staff mode as vanilla did not clean up patrol areas when switching from patrol to walk
// without doing this we could accidentally add a patrol when it didn't exist.
2023-01-22 20:16:41 +01:00
if (_s6.StaffModes[staffId] != StaffMode::Patrol)
{
return;
}
int32_t peepOffset = staffId * Limits::PatrolAreaSize;
for (int32_t i = 0; i < Limits::PatrolAreaSize; i++)
{
2023-01-22 20:16:41 +01:00
if (_s6.PatrolAreas[peepOffset + i] == 0)
{
// No patrol for this area
continue;
}
// Loop over the bits of the uint32_t
for (int32_t j = 0; j < 32; j++)
{
2023-01-22 20:16:41 +01:00
int8_t bit = (_s6.PatrolAreas[peepOffset + i] >> j) & 1;
if (bit == 0)
{
// No patrol for this area
continue;
}
// val contains the 6 highest bits of both the x and y coordinates
int32_t val = j | (i << 5);
int32_t x = val & 0x03F;
x <<= 7;
int32_t y = val & 0xFC0;
y <<= 1;
staffmember->SetPatrolArea(
MapRange(x, y, x + (4 * COORDS_XY_STEP) - 1, y + (4 * COORDS_XY_STEP) - 1), true);
}
}
}
void ImportEntities()
2019-02-18 18:20:01 +01:00
{
for (int32_t i = 0; i < GetMaxEntities(); i++)
{
2023-01-22 20:16:41 +01:00
ImportEntity(_s6.Entities[i].Unknown);
}
2019-02-18 18:20:01 +01:00
}
uint16_t GetMaxEntities()
{
2023-01-22 20:16:41 +01:00
return (_s6.Header.ClassicFlag == 0xf) ? Limits::MaxEntitiesRCTCExtended : Limits::MaxEntities;
}
template<typename OpenRCT2_T> void ImportEntity(const RCT12EntityBase& src);
void ImportEntityPeep(::Peep* dst, const Peep* src)
{
2023-01-21 23:32:44 +01:00
const auto isNullLocation = [](const RCT12xyzd8& pos) {
return pos.x == 0xFF && pos.y == 0xFF && pos.z == 0xFF && pos.direction == INVALID_DIRECTION;
};
ImportEntityCommonProperties(static_cast<EntityBase*>(dst), src);
2023-01-22 20:16:41 +01:00
if (IsUserStringID(src->NameStringIdx))
{
dst->SetName(GetUserString(src->NameStringIdx));
}
dst->NextLoc = { src->NextX, src->NextY, src->NextZ * COORDS_Z_STEP };
dst->NextFlags = src->NextFlags;
dst->State = static_cast<PeepState>(src->State);
dst->SubState = src->SubState;
dst->SpriteType = static_cast<PeepSpriteType>(src->SpriteType);
dst->TshirtColour = src->TshirtColour;
dst->TrousersColour = src->TrousersColour;
dst->DestinationX = src->DestinationX;
dst->DestinationY = src->DestinationY;
dst->DestinationTolerance = src->DestinationTolerance;
dst->Var37 = src->Var37;
dst->Energy = src->Energy;
dst->EnergyTarget = src->EnergyTarget;
dst->Mass = src->Mass;
dst->WindowInvalidateFlags = src->WindowInvalidateFlags;
dst->CurrentRide = RCT12RideIdToOpenRCT2RideId(src->CurrentRide);
dst->CurrentRideStation = StationIndex::FromUnderlying(src->CurrentRideStation);
dst->CurrentTrain = src->CurrentTrain;
dst->TimeToSitdown = src->TimeToSitdown;
dst->SpecialSprite = src->SpecialSprite;
dst->ActionSpriteType = static_cast<PeepActionSpriteType>(src->ActionSpriteType);
dst->NextActionSpriteType = static_cast<PeepActionSpriteType>(src->NextActionSpriteType);
dst->ActionSpriteImageOffset = src->ActionSpriteImageOffset;
dst->Action = static_cast<PeepActionType>(src->Action);
dst->ActionFrame = src->ActionFrame;
dst->StepProgress = src->StepProgress;
dst->PeepDirection = src->Direction;
dst->InteractionRideIndex = RCT12RideIdToOpenRCT2RideId(src->InteractionRideIndex);
dst->PeepId = src->Id;
2023-01-22 20:16:41 +01:00
dst->PathCheckOptimisation = src->PathCheckOptimisation;
dst->PeepFlags = src->PeepFlags;
if (isNullLocation(src->PathfindGoal))
{
dst->PathfindGoal.SetNull();
dst->PathfindGoal.direction = INVALID_DIRECTION;
}
else
{
2023-01-22 20:16:41 +01:00
dst->PathfindGoal = { src->PathfindGoal.x, src->PathfindGoal.y, src->PathfindGoal.z,
src->PathfindGoal.direction };
}
2023-01-22 20:16:41 +01:00
for (size_t i = 0; i < std::size(src->PathfindHistory); i++)
{
2023-01-22 20:16:41 +01:00
if (isNullLocation(src->PathfindHistory[i]))
{
dst->PathfindHistory[i].SetNull();
dst->PathfindHistory[i].direction = INVALID_DIRECTION;
}
else
{
2023-01-22 20:16:41 +01:00
dst->PathfindHistory[i] = { src->PathfindHistory[i].x, src->PathfindHistory[i].y, src->PathfindHistory[i].z,
src->PathfindHistory[i].direction };
}
}
2023-01-22 20:16:41 +01:00
dst->WalkingFrameNum = src->NoActionFrameNum;
}
constexpr EntityType GetEntityTypeFromRCT2Sprite(const RCT12EntityBase* src)
{
EntityType output = EntityType::Null;
switch (src->EntityIdentifier)
{
case RCT12EntityIdentifier::Vehicle:
output = EntityType::Vehicle;
break;
case RCT12EntityIdentifier::Peep:
2023-01-22 20:16:41 +01:00
{
const auto& peep = static_cast<const Peep&>(*src);
if (RCT12PeepType(peep.PeepType) == RCT12PeepType::Guest)
{
output = EntityType::Guest;
}
else
{
output = EntityType::Staff;
}
break;
2023-01-22 20:16:41 +01:00
}
case RCT12EntityIdentifier::Misc:
2023-01-22 20:16:41 +01:00
switch (RCT12MiscEntityType(src->Type))
{
case RCT12MiscEntityType::SteamParticle:
output = EntityType::SteamParticle;
break;
case RCT12MiscEntityType::MoneyEffect:
output = EntityType::MoneyEffect;
break;
case RCT12MiscEntityType::CrashedVehicleParticle:
output = EntityType::CrashedVehicleParticle;
break;
case RCT12MiscEntityType::ExplosionCloud:
output = EntityType::ExplosionCloud;
break;
case RCT12MiscEntityType::CrashSplash:
output = EntityType::CrashSplash;
break;
case RCT12MiscEntityType::ExplosionFlare:
output = EntityType::ExplosionFlare;
break;
case RCT12MiscEntityType::JumpingFountainWater:
case RCT12MiscEntityType::JumpingFountainSnow:
output = EntityType::JumpingFountain;
break;
case RCT12MiscEntityType::Balloon:
output = EntityType::Balloon;
break;
case RCT12MiscEntityType::Duck:
output = EntityType::Duck;
break;
default:
break;
}
break;
case RCT12EntityIdentifier::Litter:
output = EntityType::Litter;
break;
default:
break;
}
return output;
}
void ImportEntityCommonProperties(EntityBase* dst, const RCT12EntityBase* src)
{
dst->Type = GetEntityTypeFromRCT2Sprite(src);
2023-04-07 18:47:26 +02:00
dst->SpriteData.HeightMin = src->SpriteHeightNegative;
2023-01-27 18:18:44 +01:00
dst->Id = EntityId::FromUnderlying(src->EntityIndex);
dst->x = src->x;
dst->y = src->y;
dst->z = src->z;
2023-04-07 18:47:26 +02:00
dst->SpriteData.Width = src->SpriteWidth;
dst->SpriteData.HeightMax = src->SpriteHeightPositive;
dst->SpriteData.SpriteRect = ScreenRect(src->SpriteLeft, src->SpriteTop, src->SpriteRight, src->SpriteBottom);
dst->Orientation = src->EntityDirection;
}
2019-07-21 03:22:03 +02:00
void ImportEntity(const RCT12EntityBase& src);
2022-07-31 14:22:58 +02:00
std::string GetUserString(StringId stringId)
{
const auto originalString = _s6.CustomStrings[stringId % 1024];
auto originalStringView = std::string_view(
originalString, RCT12::GetRCTStringBufferLen(originalString, USER_STRING_MAX_LENGTH));
auto asUtf8 = RCT2StringToUTF8(originalStringView, RCT2LanguageId::EnglishUK);
auto justText = RCT12RemoveFormattingUTF8(asUtf8);
return justText.data();
}
ObjectList GetRequiredObjects()
{
std::fill(std::begin(_pathToSurfaceMap), std::end(_pathToSurfaceMap), OBJECT_ENTRY_INDEX_NULL);
std::fill(std::begin(_pathToQueueSurfaceMap), std::end(_pathToQueueSurfaceMap), OBJECT_ENTRY_INDEX_NULL);
std::fill(std::begin(_pathToRailingMap), std::end(_pathToRailingMap), OBJECT_ENTRY_INDEX_NULL);
ObjectList objectList;
int objectIt = 0;
ObjectEntryIndex surfaceCount = 0;
ObjectEntryIndex railingCount = 0;
for (int16_t objectType = EnumValue(ObjectType::Ride); objectType <= EnumValue(ObjectType::Water); objectType++)
2021-09-13 20:24:42 +02:00
{
2023-01-22 20:16:41 +01:00
for (int16_t i = 0; i < RCT2ObjectEntryGroupCounts[objectType]; i++, objectIt++)
{
auto entry = ObjectEntryDescriptor(_s6.Objects[objectIt]);
if (entry.HasValue())
{
if (objectType == EnumValue(ObjectType::Paths))
{
auto footpathMapping = GetFootpathSurfaceId(entry);
if (footpathMapping == nullptr)
{
// Unsupported footpath
objectList.SetObject(i, entry);
}
else
{
// We have surface objects for this footpath
auto surfaceIndex = objectList.Find(
ObjectType::FootpathSurface, footpathMapping->NormalSurface);
if (surfaceIndex == OBJECT_ENTRY_INDEX_NULL)
{
objectList.SetObject(
ObjectType::FootpathSurface, surfaceCount, footpathMapping->NormalSurface);
surfaceIndex = surfaceCount++;
}
_pathToSurfaceMap[i] = surfaceIndex;
surfaceIndex = objectList.Find(ObjectType::FootpathSurface, footpathMapping->QueueSurface);
if (surfaceIndex == OBJECT_ENTRY_INDEX_NULL)
{
objectList.SetObject(
ObjectType::FootpathSurface, surfaceCount, footpathMapping->QueueSurface);
surfaceIndex = surfaceCount++;
}
_pathToQueueSurfaceMap[i] = surfaceIndex;
auto railingIndex = objectList.Find(ObjectType::FootpathRailings, footpathMapping->Railing);
if (railingIndex == OBJECT_ENTRY_INDEX_NULL)
{
objectList.SetObject(ObjectType::FootpathRailings, railingCount, footpathMapping->Railing);
railingIndex = railingCount++;
}
_pathToRailingMap[i] = railingIndex;
}
}
else
{
objectList.SetObject(i, entry);
}
}
}
2021-09-13 20:24:42 +02:00
}
// Add default rct2 terrain surfaces and edges
AddDefaultEntries();
// Find if any rct1 terrain surfaces or edges have been used
const bool hasRCT1Terrain = std::any_of(
2023-01-22 20:16:41 +01:00
std::begin(_s6.TileElements), std::end(_s6.TileElements), [](RCT12TileElement& tile) {
auto* surface = tile.AsSurface();
if (surface == nullptr)
{
return false;
}
if (surface->GetSurfaceStyle() >= std::size(RCT2::DefaultTerrainSurfaces))
{
return true;
}
if (surface->GetEdgeStyle() >= std::size(RCT2::DefaultTerrainEdges))
{
return true;
}
return false;
});
// If an rct1 surface or edge then load all the Hybrid surfaces and edges
if (hasRCT1Terrain)
{
_terrainSurfaceEntries.AddRange(OpenRCT2HybridTerrainSurfaces);
_terrainEdgeEntries.AddRange(OpenRCT2HybridTerrainEdges);
}
AppendRequiredObjects(objectList, ObjectType::TerrainSurface, _terrainSurfaceEntries);
AppendRequiredObjects(objectList, ObjectType::TerrainEdge, _terrainEdgeEntries);
RCT12AddDefaultObjects(objectList);
return objectList;
}
};
2017-01-23 14:00:46 +01:00
template<> void S6Importer::ImportEntity<::Vehicle>(const RCT12EntityBase& baseSrc)
{
auto dst = CreateEntityAt<::Vehicle>(EntityId::FromUnderlying(baseSrc.EntityIndex));
auto src = static_cast<const RCT2::Vehicle*>(&baseSrc);
2023-01-22 20:16:41 +01:00
const auto& ride = _s6.Rides[src->Ride];
ImportEntityCommonProperties(dst, src);
2023-01-22 20:16:41 +01:00
dst->SubType = ::Vehicle::Type(src->Type);
dst->Pitch = src->Pitch;
2023-01-22 20:16:41 +01:00
dst->bank_rotation = src->BankRotation;
dst->remaining_distance = src->RemainingDistance;
dst->velocity = src->Velocity;
dst->acceleration = src->Acceleration;
dst->ride = RideId::FromUnderlying(src->Ride);
dst->vehicle_type = src->VehicleType;
dst->colours.Body = src->Colours.BodyColour;
dst->colours.Trim = src->Colours.TrimColour;
dst->colours.Tertiary = src->ColoursExtended;
dst->track_progress = src->TrackProgress;
dst->TrackLocation = { src->TrackX, src->TrackY, src->TrackZ };
if (src->BoatLocation.IsNull() || static_cast<RideMode>(ride.Mode) != RideMode::BoatHire
|| src->Status != static_cast<uint8_t>(::Vehicle::Status::TravellingBoat))
{
dst->BoatLocation.SetNull();
dst->SetTrackDirection(src->GetTrackDirection());
dst->SetTrackType(src->GetTrackType());
// RotationControlToggle and Booster are saved as the same track piece ID
// Which one the vehicle is using must be determined
2023-01-22 20:16:41 +01:00
if (IsFlatRide(src->Ride))
{
dst->SetTrackType(RCT12FlatTrackTypeToOpenRCT2(src->GetTrackType()));
}
else if (src->GetTrackType() == TrackElemType::RotationControlToggleAlias)
{
// Merging hacks mean the track type that's appropriate for the ride type is not necessarily the track type the
// ride is on. It's possible to create unwanted behavior if a user layers spinning control track on top of
// booster track but this is unlikely since only two rides have spinning control track - by default they load as
// booster
TileElement* tileElement2 = MapGetTrackElementAtOfTypeSeq(
dst->TrackLocation, TrackElemType::RotationControlToggle, 0);
if (tileElement2 != nullptr)
dst->SetTrackType(TrackElemType::RotationControlToggle);
}
else if (src->GetTrackType() == TrackElemType::BlockBrakes)
{
dst->brake_speed = kRCT2DefaultBlockBrakeSpeed;
}
}
else
{
2023-01-22 20:16:41 +01:00
dst->BoatLocation = TileCoordsXY{ src->BoatLocation.x, src->BoatLocation.y }.ToCoordsXY();
dst->SetTrackDirection(0);
dst->SetTrackType(0);
}
2023-01-22 20:16:41 +01:00
dst->next_vehicle_on_train = EntityId::FromUnderlying(src->NextVehicleOnTrain);
dst->prev_vehicle_on_ride = EntityId::FromUnderlying(src->PrevVehicleOnRide);
dst->next_vehicle_on_ride = EntityId::FromUnderlying(src->NextVehicleOnRide);
dst->var_44 = src->Var44;
dst->mass = src->Mass;
dst->Flags = src->UpdateFlags;
dst->SwingSprite = src->SwingSprite;
2023-01-22 20:16:41 +01:00
dst->current_station = StationIndex::FromUnderlying(src->CurrentStation);
dst->current_time = src->CurrentTime;
dst->crash_z = src->CrashZ;
::Vehicle::Status statusSrc = ::Vehicle::Status::MovingToEndOfStation;
2023-01-22 20:16:41 +01:00
if (src->Status <= static_cast<uint8_t>(::Vehicle::Status::StoppedByBlockBrakes))
{
2023-01-22 20:16:41 +01:00
statusSrc = static_cast<::Vehicle::Status>(src->Status);
}
dst->status = statusSrc;
2023-01-22 20:16:41 +01:00
dst->sub_state = src->SubState;
for (size_t i = 0; i < std::size(src->Peep); i++)
{
2023-01-22 20:16:41 +01:00
dst->peep[i] = EntityId::FromUnderlying(src->Peep[i]);
dst->peep_tshirt_colours[i] = src->PeepTshirtColours[i];
}
2023-01-22 20:16:41 +01:00
dst->num_seats = src->NumSeats;
dst->num_peeps = src->NumPeeps;
dst->next_free_seat = src->NextFreeSeat;
dst->restraints_position = src->RestraintsPosition;
dst->crash_x = src->CrashX;
dst->sound2_flags = src->Sound2Flags;
dst->spin_sprite = src->SpinSprite;
dst->sound1_id = static_cast<OpenRCT2::Audio::SoundId>(src->Sound1Id);
dst->sound1_volume = src->Sound1Volume;
dst->sound2_id = static_cast<OpenRCT2::Audio::SoundId>(src->Sound2Id);
dst->sound2_volume = src->Sound2Volume;
dst->sound_vector_factor = src->SoundVectorFactor;
dst->time_waiting = src->TimeWaiting;
dst->speed = src->Speed;
dst->powered_acceleration = src->PoweredAcceleration;
2022-02-23 00:14:42 +01:00
dst->CollisionDetectionTimer = src->CollisionDetectionTimer;
2023-01-22 20:16:41 +01:00
dst->animation_frame = src->AnimationFrame;
dst->animationState = src->AnimationState;
dst->scream_sound_id = static_cast<OpenRCT2::Audio::SoundId>(src->ScreamSoundId);
dst->TrackSubposition = VehicleTrackSubposition{ src->TrackSubposition };
2022-02-21 03:20:06 +01:00
dst->NumLaps = src->NumLaps;
2023-01-22 20:16:41 +01:00
dst->brake_speed = src->BrakeSpeed;
dst->lost_time_out = src->LostTimeOut;
dst->vertical_drop_countdown = src->VerticalDropCountdown;
dst->var_D3 = src->VarD3;
dst->mini_golf_current_animation = MiniGolfAnimation(src->MiniGolfCurrentAnimation);
dst->mini_golf_flags = src->MiniGolfFlags;
dst->ride_subtype = RCTEntryIndexToOpenRCT2EntryIndex(src->RideSubtype);
dst->seat_rotation = src->SeatRotation;
dst->target_seat_rotation = src->TargetSeatRotation;
if (src->Flags & RCT12_ENTITY_FLAGS_IS_CRASHED_VEHICLE_ENTITY)
{
dst->SetFlag(VehicleFlags::Crashed);
}
dst->BlockBrakeSpeed = kRCT2DefaultBlockBrakeSpeed;
}
static uint32_t AdjustScenarioToCurrentTicks(const S6Data& s6, uint32_t tick)
{
// Previously gScenarioTicks was used as a time point, now it's gCurrentTicks.
// gCurrentTicks and gScenarioTicks are now exported as the same, older saves that have a different
// scenario tick must account for the difference between the two.
2023-01-22 20:16:41 +01:00
uint32_t ticksElapsed = s6.ScenarioTicks - tick;
return s6.GameTicks1 - ticksElapsed;
}
template<> void S6Importer::ImportEntity<::Guest>(const RCT12EntityBase& baseSrc)
{
auto dst = CreateEntityAt<::Guest>(EntityId::FromUnderlying(baseSrc.EntityIndex));
auto src = static_cast<const Peep*>(&baseSrc);
ImportEntityPeep(dst, src);
2023-01-22 20:16:41 +01:00
dst->OutsideOfPark = static_cast<bool>(src->OutsideOfPark);
dst->GuestNumRides = src->NoOfRides;
dst->Happiness = src->Happiness;
dst->HappinessTarget = src->HappinessTarget;
dst->Nausea = src->Nausea;
dst->NauseaTarget = src->NauseaTarget;
dst->Hunger = src->Hunger;
dst->Thirst = src->Thirst;
dst->Toilet = src->Toilet;
dst->TimeToConsume = src->TimeToConsume;
dst->Intensity = static_cast<IntensityRange>(src->Intensity);
dst->NauseaTolerance = static_cast<PeepNauseaTolerance>(src->NauseaTolerance);
dst->PaidOnDrink = src->PaidOnDrink;
2023-01-27 18:18:44 +01:00
OpenRCT2::RideUse::GetHistory().Set(dst->Id, RCT12GetRidesBeenOn(src));
OpenRCT2::RideUse::GetTypeHistory().Set(dst->Id, RCT12GetRideTypesBeenOn(src));
dst->SetItemFlags(src->GetItemFlags());
2023-01-22 20:16:41 +01:00
dst->Photo1RideRef = RCT12RideIdToOpenRCT2RideId(src->Photo1RideRef);
dst->Photo2RideRef = RCT12RideIdToOpenRCT2RideId(src->Photo2RideRef);
dst->Photo3RideRef = RCT12RideIdToOpenRCT2RideId(src->Photo3RideRef);
dst->Photo4RideRef = RCT12RideIdToOpenRCT2RideId(src->Photo4RideRef);
dst->GuestNextInQueue = EntityId::FromUnderlying(src->NextInQueue);
dst->TimeInQueue = src->TimeInQueue;
dst->CashInPocket = src->CashInPocket;
dst->CashSpent = src->CashSpent;
dst->ParkEntryTime = AdjustScenarioToCurrentTicks(_s6, src->ParkEntryTime);
dst->RejoinQueueTimeout = src->RejoinQueueTimeout;
dst->PreviousRide = RCT12RideIdToOpenRCT2RideId(src->PreviousRide);
dst->PreviousRideTimeOut = src->PreviousRideTimeOut;
for (size_t i = 0; i < std::size(src->Thoughts); i++)
{
2023-01-22 20:16:41 +01:00
auto srcThought = &src->Thoughts[i];
auto dstThought = &dst->Thoughts[i];
2023-01-22 20:16:41 +01:00
dstThought->type = static_cast<PeepThoughtType>(srcThought->Type);
if (srcThought->Item == RCT12PeepThoughtItemNone)
dstThought->item = PeepThoughtItemNone;
else
2023-01-22 20:16:41 +01:00
dstThought->item = srcThought->Item;
dstThought->freshness = srcThought->Freshness;
dstThought->fresh_timeout = srcThought->FreshTimeout;
}
2023-01-22 20:16:41 +01:00
dst->GuestHeadingToRideId = RCT12RideIdToOpenRCT2RideId(src->GuestHeadingToRideId);
dst->GuestIsLostCountdown = src->PeepIsLostCountdown;
dst->LitterCount = src->LitterCount;
dst->GuestTimeOnRide = src->TimeOnRide;
dst->DisgustingCount = src->DisgustingCount;
dst->PaidToEnter = src->PaidToEnter;
dst->PaidOnRides = src->PaidOnRides;
dst->PaidOnFood = src->PaidOnFood;
dst->PaidOnSouvenirs = src->PaidOnSouvenirs;
dst->AmountOfFood = src->NoOfFood;
dst->AmountOfDrinks = src->NoOfDrinks;
dst->AmountOfSouvenirs = src->NoOfSouvenirs;
dst->VandalismSeen = src->VandalismSeen;
dst->VoucherType = src->VoucherType;
dst->VoucherRideId = RCT12RideIdToOpenRCT2RideId(src->VoucherArguments);
dst->SurroundingsThoughtTimeout = src->SurroundingsThoughtTimeout;
dst->Angriness = src->Angriness;
dst->TimeLost = src->TimeLost;
dst->DaysInQueue = src->DaysInQueue;
dst->BalloonColour = src->BalloonColour;
dst->UmbrellaColour = src->UmbrellaColour;
dst->HatColour = src->HatColour;
dst->FavouriteRide = RCT12RideIdToOpenRCT2RideId(src->FavouriteRide);
dst->FavouriteRideRating = src->FavouriteRideRating;
}
template<> void S6Importer::ImportEntity<::Staff>(const RCT12EntityBase& baseSrc)
{
auto dst = CreateEntityAt<::Staff>(EntityId::FromUnderlying(baseSrc.EntityIndex));
auto src = static_cast<const Peep*>(&baseSrc);
ImportEntityPeep(dst, src);
2023-01-22 20:16:41 +01:00
dst->AssignedStaffType = StaffType(src->StaffType);
dst->MechanicTimeSinceCall = src->MechanicTimeSinceCall;
2023-01-22 20:16:41 +01:00
dst->HireDate = src->ParkEntryTime;
dst->StaffOrders = src->StaffOrders;
dst->StaffMowingTimeout = src->StaffMowingTimeout;
dst->StaffLawnsMown = src->PaidToEnter;
dst->StaffGardensWatered = src->PaidOnRides;
dst->StaffLitterSwept = src->PaidOnFood;
dst->StaffBinsEmptied = src->PaidOnSouvenirs;
2023-01-22 20:16:41 +01:00
ImportStaffPatrolArea(dst, src->StaffId);
}
template<> void S6Importer::ImportEntity<::SteamParticle>(const RCT12EntityBase& baseSrc)
{
auto dst = CreateEntityAt<::SteamParticle>(EntityId::FromUnderlying(baseSrc.EntityIndex));
auto src = static_cast<const RCT12EntitySteamParticle*>(&baseSrc);
ImportEntityCommonProperties(dst, src);
2023-01-22 20:16:41 +01:00
dst->time_to_move = src->TimeToMove;
dst->frame = src->Frame;
}
template<> void S6Importer::ImportEntity<::MoneyEffect>(const RCT12EntityBase& baseSrc)
{
auto dst = CreateEntityAt<::MoneyEffect>(EntityId::FromUnderlying(baseSrc.EntityIndex));
auto src = static_cast<const RCT12EntityMoneyEffect*>(&baseSrc);
ImportEntityCommonProperties(dst, src);
2023-01-22 20:16:41 +01:00
dst->MoveDelay = src->MoveDelay;
dst->NumMovements = src->NumMovements;
dst->GuestPurchase = src->Vertical;
2023-01-22 20:16:41 +01:00
dst->Value = src->Value;
dst->OffsetX = src->OffsetX;
dst->Wiggle = src->Wiggle;
}
template<> void S6Importer::ImportEntity<::VehicleCrashParticle>(const RCT12EntityBase& baseSrc)
{
auto dst = CreateEntityAt<::VehicleCrashParticle>(EntityId::FromUnderlying(baseSrc.EntityIndex));
auto src = static_cast<const RCT12EntityCrashedVehicleParticle*>(&baseSrc);
ImportEntityCommonProperties(dst, src);
2023-01-22 20:16:41 +01:00
dst->frame = src->Frame;
dst->time_to_live = src->TimeToLive;
dst->frame = src->Frame;
dst->colour[0] = src->Colour[0];
dst->colour[1] = src->Colour[1];
dst->crashed_sprite_base = src->CrashedEntityBase;
2023-01-22 20:16:41 +01:00
dst->velocity_x = src->VelocityX;
dst->velocity_y = src->VelocityY;
dst->velocity_z = src->VelocityZ;
dst->acceleration_x = src->AccelerationX;
dst->acceleration_y = src->AccelerationY;
dst->acceleration_z = src->AccelerationZ;
}
template<> void S6Importer::ImportEntity<::ExplosionCloud>(const RCT12EntityBase& baseSrc)
{
auto dst = CreateEntityAt<::ExplosionCloud>(EntityId::FromUnderlying(baseSrc.EntityIndex));
auto src = static_cast<const RCT12EntityParticle*>(&baseSrc);
ImportEntityCommonProperties(dst, src);
2023-01-22 20:16:41 +01:00
dst->frame = src->Frame;
}
template<> void S6Importer::ImportEntity<::ExplosionFlare>(const RCT12EntityBase& baseSrc)
{
auto dst = CreateEntityAt<::ExplosionFlare>(EntityId::FromUnderlying(baseSrc.EntityIndex));
auto src = static_cast<const RCT12EntityParticle*>(&baseSrc);
ImportEntityCommonProperties(dst, src);
2023-01-22 20:16:41 +01:00
dst->frame = src->Frame;
}
template<> void S6Importer::ImportEntity<::CrashSplashParticle>(const RCT12EntityBase& baseSrc)
{
auto dst = CreateEntityAt<::CrashSplashParticle>(EntityId::FromUnderlying(baseSrc.EntityIndex));
auto src = static_cast<const RCT12EntityParticle*>(&baseSrc);
ImportEntityCommonProperties(dst, src);
2023-01-22 20:16:41 +01:00
dst->frame = src->Frame;
}
template<> void S6Importer::ImportEntity<::JumpingFountain>(const RCT12EntityBase& baseSrc)
{
auto dst = CreateEntityAt<::JumpingFountain>(EntityId::FromUnderlying(baseSrc.EntityIndex));
auto src = static_cast<const RCT12EntityJumpingFountain*>(&baseSrc);
ImportEntityCommonProperties(dst, src);
2023-01-22 20:16:41 +01:00
dst->NumTicksAlive = src->NumTicksAlive;
dst->frame = src->Frame;
dst->FountainFlags = src->FountainFlags;
dst->TargetX = src->TargetX;
dst->TargetY = src->TargetY;
dst->Iteration = src->Iteration;
dst->FountainType = RCT12MiscEntityType(src->Type) == RCT12MiscEntityType::JumpingFountainSnow
? ::JumpingFountainType::Snow
: ::JumpingFountainType::Water;
}
template<> void S6Importer::ImportEntity<::Balloon>(const RCT12EntityBase& baseSrc)
{
auto dst = CreateEntityAt<::Balloon>(EntityId::FromUnderlying(baseSrc.EntityIndex));
auto src = static_cast<const RCT12EntityBalloon*>(&baseSrc);
ImportEntityCommonProperties(dst, src);
2023-01-22 20:16:41 +01:00
dst->popped = src->Popped;
dst->time_to_move = src->TimeToMove;
dst->frame = src->Frame;
dst->colour = src->Colour;
}
template<> void S6Importer::ImportEntity<::Duck>(const RCT12EntityBase& baseSrc)
{
auto dst = CreateEntityAt<::Duck>(EntityId::FromUnderlying(baseSrc.EntityIndex));
auto src = static_cast<const RCT12EntityDuck*>(&baseSrc);
ImportEntityCommonProperties(dst, src);
2023-01-22 20:16:41 +01:00
dst->frame = src->Frame;
dst->target_x = src->TargetX;
dst->target_y = src->TargetY;
dst->state = static_cast<::Duck::DuckState>(src->State);
}
template<> void S6Importer::ImportEntity<::Litter>(const RCT12EntityBase& baseSrc)
{
auto dst = CreateEntityAt<::Litter>(EntityId::FromUnderlying(baseSrc.EntityIndex));
auto src = static_cast<const RCT12EntityLitter*>(&baseSrc);
ImportEntityCommonProperties(dst, src);
2023-01-22 20:16:41 +01:00
dst->SubType = ::Litter::Type(src->Type);
dst->creationTick = AdjustScenarioToCurrentTicks(_s6, src->CreationTick);
}
void S6Importer::ImportEntity(const RCT12EntityBase& src)
{
switch (GetEntityTypeFromRCT2Sprite(&src))
{
case EntityType::Vehicle:
ImportEntity<::Vehicle>(src);
break;
case EntityType::Guest:
ImportEntity<::Guest>(src);
break;
case EntityType::Staff:
ImportEntity<::Staff>(src);
break;
case EntityType::SteamParticle:
ImportEntity<::SteamParticle>(src);
break;
case EntityType::MoneyEffect:
ImportEntity<::MoneyEffect>(src);
break;
case EntityType::CrashedVehicleParticle:
ImportEntity<::VehicleCrashParticle>(src);
break;
case EntityType::ExplosionCloud:
ImportEntity<::ExplosionCloud>(src);
break;
case EntityType::ExplosionFlare:
ImportEntity<::ExplosionFlare>(src);
break;
case EntityType::CrashSplash:
ImportEntity<::CrashSplashParticle>(src);
break;
case EntityType::JumpingFountain:
ImportEntity<::JumpingFountain>(src);
break;
case EntityType::Balloon:
ImportEntity<::Balloon>(src);
break;
case EntityType::Duck:
ImportEntity<::Duck>(src);
break;
case EntityType::Litter:
ImportEntity<::Litter>(src);
break;
default:
// Null elements do not need imported
break;
}
}
} // namespace RCT2
2018-08-29 09:30:36 +02:00
std::unique_ptr<IParkImporter> ParkImporter::CreateS6(IObjectRepository& objectRepository)
{
return std::make_unique<RCT2::S6Importer>(objectRepository);
}