mirror of
https://github.com/OpenRCT2/OpenRCT2
synced 2026-01-28 17:24:47 +01:00
Move most command logic from sequence player
This commit also moves everything related to the OpenRCT2::Title namespace. Can be compiled with ENABLE_SCRIPTING disabled.
This commit is contained in:
@@ -710,7 +710,7 @@ public:
|
||||
{
|
||||
auto context = GetContext();
|
||||
auto gameState = context->GetGameState();
|
||||
_titleSequencePlayer = CreateTitleSequencePlayer(*gameState);
|
||||
_titleSequencePlayer = OpenRCT2::Title::CreateTitleSequencePlayer(*gameState);
|
||||
}
|
||||
return _titleSequencePlayer.get();
|
||||
}
|
||||
|
||||
@@ -39,489 +39,376 @@
|
||||
#include <openrct2/windows/Intent.h>
|
||||
#include <openrct2/world/Map.h>
|
||||
#include <openrct2/world/Scenery.h>
|
||||
#include <stdexcept>
|
||||
|
||||
using namespace OpenRCT2;
|
||||
|
||||
class TitleSequencePlayer final : public ITitleSequencePlayer
|
||||
namespace OpenRCT2::Title
|
||||
{
|
||||
private:
|
||||
GameState& _gameState;
|
||||
|
||||
std::unique_ptr<TitleSequence> _sequence;
|
||||
int32_t _position = 0;
|
||||
int32_t _waitCounter = 0;
|
||||
|
||||
int32_t _lastScreenWidth = 0;
|
||||
int32_t _lastScreenHeight = 0;
|
||||
CoordsXY _viewCentreLocation = {};
|
||||
|
||||
public:
|
||||
explicit TitleSequencePlayer(GameState& gameState)
|
||||
: _gameState(gameState)
|
||||
class TitleSequencePlayer final : public ITitleSequencePlayer
|
||||
{
|
||||
}
|
||||
private:
|
||||
GameState& _gameState;
|
||||
|
||||
~TitleSequencePlayer() override
|
||||
{
|
||||
Eject();
|
||||
}
|
||||
std::unique_ptr<TitleSequence> _sequence;
|
||||
int32_t _position = 0;
|
||||
int32_t _waitCounter = 0;
|
||||
|
||||
int32_t GetCurrentPosition() const override
|
||||
{
|
||||
return _position;
|
||||
}
|
||||
int32_t _lastScreenWidth = 0;
|
||||
int32_t _lastScreenHeight = 0;
|
||||
CoordsXY _viewCentreLocation = {};
|
||||
|
||||
void Eject() override
|
||||
{
|
||||
_sequence = nullptr;
|
||||
}
|
||||
|
||||
bool Begin(size_t titleSequenceId) override
|
||||
{
|
||||
size_t numSequences = TitleSequenceManager::GetCount();
|
||||
if (titleSequenceId >= numSequences)
|
||||
public:
|
||||
explicit TitleSequencePlayer(GameState& gameState)
|
||||
: _gameState(gameState)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
auto seqItem = TitleSequenceManager::GetItem(titleSequenceId);
|
||||
auto sequence = LoadTitleSequence(seqItem->Path);
|
||||
if (sequence == nullptr)
|
||||
~TitleSequencePlayer() override
|
||||
{
|
||||
return false;
|
||||
Eject();
|
||||
}
|
||||
|
||||
Eject();
|
||||
_sequence = std::move(sequence);
|
||||
|
||||
Reset();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Update() override
|
||||
{
|
||||
int32_t entryPosition = _position;
|
||||
FixViewLocation();
|
||||
|
||||
if (_sequence == nullptr)
|
||||
int32_t GetCurrentPosition() const override
|
||||
{
|
||||
SetViewLocation(TileCoordsXY(75, 75).ToCoordsXY());
|
||||
return false;
|
||||
return _position;
|
||||
}
|
||||
|
||||
// Check that position is valid
|
||||
if (_position >= static_cast<int32_t>(_sequence->Commands.size()))
|
||||
void Eject() override
|
||||
{
|
||||
_position = 0;
|
||||
return false;
|
||||
_sequence = nullptr;
|
||||
}
|
||||
|
||||
// Don't execute next command until we are done with the current wait command
|
||||
if (_waitCounter != 0)
|
||||
bool Begin(size_t titleSequenceId) override
|
||||
{
|
||||
_waitCounter--;
|
||||
if (_waitCounter == 0)
|
||||
size_t numSequences = TitleSequenceManager::GetCount();
|
||||
if (titleSequenceId >= numSequences)
|
||||
{
|
||||
const auto& command = _sequence->Commands[_position];
|
||||
if (command.Type == TitleScript::Wait)
|
||||
{
|
||||
IncrementPosition();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
auto seqItem = TitleSequenceManager::GetItem(titleSequenceId);
|
||||
auto sequence = LoadTitleSequence(seqItem->Path);
|
||||
if (sequence == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Eject();
|
||||
_sequence = std::move(sequence);
|
||||
|
||||
Reset();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
|
||||
bool Update() override
|
||||
{
|
||||
FixViewLocation();
|
||||
|
||||
if (_sequence == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Run commands in order, until we reach one that is not instantly done
|
||||
int32_t entryPosition = _position;
|
||||
while (true)
|
||||
{
|
||||
const auto& command = _sequence->Commands[_position];
|
||||
if (ExecuteCommand(command))
|
||||
auto& currentCommand = _sequence->Commands[_position];
|
||||
try
|
||||
{
|
||||
if (command.Type == TitleScript::Wait)
|
||||
int framesToWait = std::visit([&](auto& command) { return command(_waitCounter); }, currentCommand);
|
||||
if (framesToWait > _waitCounter)
|
||||
{
|
||||
break;
|
||||
_waitCounter++;
|
||||
return true;
|
||||
}
|
||||
if (command.Type != TitleScript::Restart)
|
||||
|
||||
// TODO: Make the loading interface simpler so these blocks can be moved to their respective command classes
|
||||
if (std::holds_alternative<LoadParkCommand>(currentCommand))
|
||||
{
|
||||
IncrementPosition();
|
||||
bool loadSuccess = false;
|
||||
const auto saveIndex = std::get<LoadParkCommand>(currentCommand).SaveIndex;
|
||||
auto parkHandle = TitleSequenceGetParkHandle(*_sequence, saveIndex);
|
||||
if (parkHandle != nullptr)
|
||||
{
|
||||
game_notify_map_change();
|
||||
loadSuccess = LoadParkFromStream(parkHandle->Stream.get(), parkHandle->HintPath);
|
||||
}
|
||||
if (!loadSuccess)
|
||||
{
|
||||
if (_sequence->Saves.size() > saveIndex)
|
||||
{
|
||||
const auto& path = _sequence->Saves[saveIndex];
|
||||
throw std::domain_error("Failed to load: \"" + path + "\" for the title sequence.");
|
||||
}
|
||||
|
||||
throw std::out_of_range("Failed to load park; index out of range.");
|
||||
}
|
||||
|
||||
game_notify_map_changed();
|
||||
}
|
||||
if (_position == entryPosition)
|
||||
else if (std::holds_alternative<LoadScenarioCommand>(currentCommand))
|
||||
{
|
||||
Console::Error::WriteLine("Infinite loop detected in title sequence.");
|
||||
Console::Error::WriteLine(" A wait command may be missing.");
|
||||
return false;
|
||||
auto& scenarioName = std::get<LoadScenarioCommand>(currentCommand).Scenario;
|
||||
bool loadSuccess = false;
|
||||
auto scenario = GetScenarioRepository()->GetByInternalName(scenarioName);
|
||||
if (scenario != nullptr)
|
||||
{
|
||||
game_notify_map_change();
|
||||
loadSuccess = LoadParkFromFile(scenario->path);
|
||||
}
|
||||
|
||||
if (!loadSuccess)
|
||||
{
|
||||
auto message = std::string("Failed to load: \"") + scenarioName + " for the title sequence.";
|
||||
throw std::domain_error(message);
|
||||
}
|
||||
|
||||
game_notify_map_changed();
|
||||
}
|
||||
}
|
||||
else
|
||||
catch (std::exception& e)
|
||||
{
|
||||
if (!SkipToNextLoadCommand() || _position == entryPosition)
|
||||
{
|
||||
Console::Error::WriteLine("Unable to load any parks from %s.", _sequence->Name.c_str());
|
||||
return false;
|
||||
}
|
||||
const char* commandName = std::visit(
|
||||
[](auto&& command) { return std::decay<decltype(command)>::type::Name; }, currentCommand);
|
||||
Console::Error::WriteLine("%s (command %i) failed with error: %s", commandName, _position, e.what());
|
||||
Console::Error::WriteLine(" Skipping to the next command.");
|
||||
}
|
||||
|
||||
IncrementPosition();
|
||||
|
||||
if (_position == entryPosition)
|
||||
{
|
||||
Console::Error::WriteLine("Infinite loop detected in title sequence.");
|
||||
Console::Error::WriteLine(" A wait command may be missing.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
_position = 0;
|
||||
_waitCounter = 0;
|
||||
}
|
||||
|
||||
void Seek(int32_t targetPosition) override
|
||||
{
|
||||
if (targetPosition < 0 || targetPosition >= static_cast<int32_t>(_sequence->Commands.size()))
|
||||
{
|
||||
throw std::runtime_error("Invalid position.");
|
||||
}
|
||||
if (_position >= targetPosition)
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
if (_sequence->Commands[targetPosition].Type == TitleScript::Restart)
|
||||
{
|
||||
targetPosition = 0;
|
||||
}
|
||||
// Set position to the last LOAD command before target position
|
||||
for (int32_t i = targetPosition; i >= 0; i--)
|
||||
{
|
||||
const TitleCommand& command = _sequence->Commands[i];
|
||||
if ((_position == i && _position != targetPosition) || TitleSequenceIsLoadCommand(command))
|
||||
{
|
||||
// Break if we have a new load command or if we're already in the range of the correct load command
|
||||
_position = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Keep updating until we reach target position
|
||||
gInUpdateCode = true;
|
||||
|
||||
while (_position < targetPosition)
|
||||
{
|
||||
if (Update())
|
||||
{
|
||||
_gameState.UpdateLogic();
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
gInUpdateCode = false;
|
||||
|
||||
_waitCounter = 0;
|
||||
}
|
||||
|
||||
private:
|
||||
void IncrementPosition()
|
||||
{
|
||||
_position++;
|
||||
if (_position >= static_cast<int32_t>(_sequence->Commands.size()))
|
||||
void Reset() override
|
||||
{
|
||||
_position = 0;
|
||||
_waitCounter = 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool SkipToNextLoadCommand()
|
||||
{
|
||||
int32_t entryPosition = _position;
|
||||
const TitleCommand* command;
|
||||
do
|
||||
void Seek(int32_t targetPosition) override
|
||||
{
|
||||
IncrementPosition();
|
||||
command = &_sequence->Commands[_position];
|
||||
} while (!TitleSequenceIsLoadCommand(*command) && _position != entryPosition);
|
||||
return _position != entryPosition;
|
||||
}
|
||||
|
||||
bool ExecuteCommand(const TitleCommand& command)
|
||||
{
|
||||
switch (command.Type)
|
||||
{
|
||||
case TitleScript::End:
|
||||
_waitCounter = 1;
|
||||
break;
|
||||
case TitleScript::Wait:
|
||||
// The waitCounter is measured in 25-ms game ticks. Previously it was seconds * 40 ticks/second, now it is ms /
|
||||
// 25 ms/tick
|
||||
_waitCounter = std::max<int32_t>(
|
||||
1, command.Milliseconds / static_cast<uint32_t>(GAME_UPDATE_TIME_MS * 1000.0f));
|
||||
break;
|
||||
case TitleScript::Location:
|
||||
if (targetPosition < 0 || targetPosition >= static_cast<int32_t>(_sequence->Commands.size()))
|
||||
{
|
||||
auto loc = TileCoordsXY(command.Location.X, command.Location.Y).ToCoordsXY().ToTileCentre();
|
||||
SetViewLocation(loc);
|
||||
break;
|
||||
throw std::runtime_error("Invalid position.");
|
||||
}
|
||||
case TitleScript::Undefined:
|
||||
break;
|
||||
case TitleScript::Loop:
|
||||
break;
|
||||
case TitleScript::EndLoop:
|
||||
break;
|
||||
case TitleScript::Rotate:
|
||||
RotateView(command.Rotations);
|
||||
break;
|
||||
case TitleScript::Zoom:
|
||||
SetViewZoom(ZoomLevel{ static_cast<int8_t>(command.Zoom) });
|
||||
break;
|
||||
case TitleScript::Speed:
|
||||
gGameSpeed = std::clamp<uint8_t>(command.Speed, 1, 4);
|
||||
break;
|
||||
case TitleScript::Follow:
|
||||
FollowSprite(command.Follow.SpriteIndex);
|
||||
break;
|
||||
case TitleScript::Restart:
|
||||
if (_position >= targetPosition)
|
||||
{
|
||||
Reset();
|
||||
break;
|
||||
case TitleScript::Load:
|
||||
}
|
||||
|
||||
if (std::holds_alternative<RestartCommand>(_sequence->Commands[targetPosition]))
|
||||
{
|
||||
bool loadSuccess = false;
|
||||
uint8_t saveIndex = command.SaveIndex;
|
||||
auto parkHandle = TitleSequenceGetParkHandle(*_sequence, saveIndex);
|
||||
if (parkHandle != nullptr)
|
||||
targetPosition = 0;
|
||||
}
|
||||
|
||||
// Set position to the last LOAD command before target position
|
||||
for (int32_t i = targetPosition; i >= 0; i--)
|
||||
{
|
||||
const TitleCommand& command = _sequence->Commands[i];
|
||||
if ((_position == i && _position != targetPosition) || TitleSequenceIsLoadCommand(command))
|
||||
{
|
||||
game_notify_map_change();
|
||||
loadSuccess = LoadParkFromStream(parkHandle->Stream.get(), parkHandle->HintPath);
|
||||
// Break if we have a new load command or if we're already in the range of the correct load command
|
||||
_position = i;
|
||||
break;
|
||||
}
|
||||
if (loadSuccess)
|
||||
}
|
||||
|
||||
// Keep updating until we reach target position
|
||||
gInUpdateCode = true;
|
||||
|
||||
while (_position < targetPosition)
|
||||
{
|
||||
if (Update())
|
||||
{
|
||||
game_notify_map_changed();
|
||||
_gameState.UpdateLogic();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_sequence->Saves.size() > saveIndex)
|
||||
{
|
||||
const auto& path = _sequence->Saves[saveIndex];
|
||||
Console::Error::WriteLine("Failed to load: \"%s\" for the title sequence.", path.c_str());
|
||||
}
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TitleScript::LoadSc:
|
||||
|
||||
gInUpdateCode = false;
|
||||
|
||||
_waitCounter = 0;
|
||||
}
|
||||
|
||||
private:
|
||||
void IncrementPosition()
|
||||
{
|
||||
_position++;
|
||||
if (_position >= static_cast<int32_t>(_sequence->Commands.size()))
|
||||
{
|
||||
bool loadSuccess = false;
|
||||
auto scenario = GetScenarioRepository()->GetByInternalName(command.Scenario);
|
||||
if (scenario != nullptr)
|
||||
_position = 0;
|
||||
}
|
||||
_waitCounter = 0;
|
||||
}
|
||||
|
||||
bool SkipToNextLoadCommand()
|
||||
{
|
||||
int32_t entryPosition = _position;
|
||||
const TitleCommand* command;
|
||||
do
|
||||
{
|
||||
IncrementPosition();
|
||||
command = &_sequence->Commands[_position];
|
||||
} while (!TitleSequenceIsLoadCommand(*command) && _position != entryPosition);
|
||||
return _position != entryPosition;
|
||||
}
|
||||
|
||||
void FollowSprite(EntityId spriteIndex)
|
||||
{
|
||||
rct_window* w = window_get_main();
|
||||
if (w != nullptr)
|
||||
{
|
||||
window_follow_sprite(w, spriteIndex);
|
||||
}
|
||||
}
|
||||
|
||||
void UnfollowSprite()
|
||||
{
|
||||
rct_window* w = window_get_main();
|
||||
if (w != nullptr)
|
||||
{
|
||||
window_unfollow_sprite(w);
|
||||
}
|
||||
}
|
||||
|
||||
bool LoadParkFromFile(const utf8* path)
|
||||
{
|
||||
log_verbose("TitleSequencePlayer::LoadParkFromFile(%s)", path);
|
||||
bool success = false;
|
||||
try
|
||||
{
|
||||
if (gPreviewingTitleSequenceInGame)
|
||||
{
|
||||
game_notify_map_change();
|
||||
loadSuccess = LoadParkFromFile(scenario->path);
|
||||
}
|
||||
if (loadSuccess)
|
||||
{
|
||||
game_notify_map_changed();
|
||||
gLoadKeepWindowsOpen = true;
|
||||
CloseParkSpecificWindows();
|
||||
context_load_park_from_file(path);
|
||||
}
|
||||
else
|
||||
{
|
||||
Console::Error::WriteLine("Failed to load: \"%s\" for the title sequence.", command.Scenario);
|
||||
return false;
|
||||
auto parkImporter = ParkImporter::Create(path);
|
||||
auto result = parkImporter->Load(path);
|
||||
|
||||
auto& objectManager = GetContext()->GetObjectManager();
|
||||
objectManager.LoadObjects(result.RequiredObjects);
|
||||
|
||||
parkImporter->Import();
|
||||
}
|
||||
break;
|
||||
PrepareParkForPlayback();
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void SetViewZoom(ZoomLevel zoom)
|
||||
{
|
||||
rct_window* w = window_get_main();
|
||||
if (w != nullptr && w->viewport != nullptr)
|
||||
{
|
||||
window_zoom_set(w, zoom, false);
|
||||
}
|
||||
}
|
||||
|
||||
void RotateView(uint32_t count)
|
||||
{
|
||||
rct_window* w = window_get_main();
|
||||
if (w != nullptr)
|
||||
{
|
||||
for (uint32_t i = 0; i < count; i++)
|
||||
catch (const std::exception&)
|
||||
{
|
||||
window_rotate_camera(w, 1);
|
||||
Console::Error::WriteLine("Unable to load park: %s", path);
|
||||
}
|
||||
gLoadKeepWindowsOpen = false;
|
||||
return success;
|
||||
}
|
||||
}
|
||||
|
||||
void FollowSprite(EntityId spriteIndex)
|
||||
{
|
||||
rct_window* w = window_get_main();
|
||||
if (w != nullptr)
|
||||
/**
|
||||
* @param stream The stream to read the park data from.
|
||||
* @param hintPath Hint path, the extension is grabbed to determine what importer to use.
|
||||
*/
|
||||
bool LoadParkFromStream(OpenRCT2::IStream* stream, const std::string& hintPath)
|
||||
{
|
||||
window_follow_sprite(w, spriteIndex);
|
||||
}
|
||||
}
|
||||
|
||||
void UnfollowSprite()
|
||||
{
|
||||
rct_window* w = window_get_main();
|
||||
if (w != nullptr)
|
||||
{
|
||||
window_unfollow_sprite(w);
|
||||
}
|
||||
}
|
||||
|
||||
bool LoadParkFromFile(const utf8* path)
|
||||
{
|
||||
log_verbose("TitleSequencePlayer::LoadParkFromFile(%s)", path);
|
||||
bool success = false;
|
||||
try
|
||||
{
|
||||
if (gPreviewingTitleSequenceInGame)
|
||||
log_verbose("TitleSequencePlayer::LoadParkFromStream(%s)", hintPath.c_str());
|
||||
bool success = false;
|
||||
try
|
||||
{
|
||||
gLoadKeepWindowsOpen = true;
|
||||
CloseParkSpecificWindows();
|
||||
context_load_park_from_file(path);
|
||||
if (gPreviewingTitleSequenceInGame)
|
||||
{
|
||||
gLoadKeepWindowsOpen = true;
|
||||
CloseParkSpecificWindows();
|
||||
context_load_park_from_stream(stream);
|
||||
}
|
||||
else
|
||||
{
|
||||
bool isScenario = ParkImporter::ExtensionIsScenario(hintPath);
|
||||
auto parkImporter = ParkImporter::Create(hintPath);
|
||||
auto result = parkImporter->LoadFromStream(stream, isScenario);
|
||||
|
||||
auto& objectManager = GetContext()->GetObjectManager();
|
||||
objectManager.LoadObjects(result.RequiredObjects);
|
||||
|
||||
parkImporter->Import();
|
||||
}
|
||||
PrepareParkForPlayback();
|
||||
success = true;
|
||||
}
|
||||
else
|
||||
catch (const std::exception&)
|
||||
{
|
||||
auto parkImporter = ParkImporter::Create(path);
|
||||
auto result = parkImporter->Load(path);
|
||||
|
||||
auto& objectManager = GetContext()->GetObjectManager();
|
||||
objectManager.LoadObjects(result.RequiredObjects);
|
||||
|
||||
parkImporter->Import();
|
||||
Console::Error::WriteLine("Unable to load park: %s", hintPath.c_str());
|
||||
}
|
||||
PrepareParkForPlayback();
|
||||
success = true;
|
||||
gLoadKeepWindowsOpen = false;
|
||||
return success;
|
||||
}
|
||||
catch (const std::exception&)
|
||||
{
|
||||
Console::Error::WriteLine("Unable to load park: %s", path);
|
||||
}
|
||||
gLoadKeepWindowsOpen = false;
|
||||
return success;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param stream The stream to read the park data from.
|
||||
* @param hintPath Hint path, the extension is grabbed to determine what importer to use.
|
||||
*/
|
||||
bool LoadParkFromStream(OpenRCT2::IStream* stream, const std::string& hintPath)
|
||||
{
|
||||
log_verbose("TitleSequencePlayer::LoadParkFromStream(%s)", hintPath.c_str());
|
||||
bool success = false;
|
||||
try
|
||||
void CloseParkSpecificWindows()
|
||||
{
|
||||
if (gPreviewingTitleSequenceInGame)
|
||||
window_close_by_class(WC_CONSTRUCT_RIDE);
|
||||
window_close_by_class(WC_DEMOLISH_RIDE_PROMPT);
|
||||
window_close_by_class(WC_EDITOR_INVENTION_LIST_DRAG);
|
||||
window_close_by_class(WC_EDITOR_INVENTION_LIST);
|
||||
window_close_by_class(WC_EDITOR_OBJECT_SELECTION);
|
||||
window_close_by_class(WC_EDITOR_OBJECTIVE_OPTIONS);
|
||||
window_close_by_class(WC_EDITOR_SCENARIO_OPTIONS);
|
||||
window_close_by_class(WC_FINANCES);
|
||||
window_close_by_class(WC_FIRE_PROMPT);
|
||||
window_close_by_class(WC_GUEST_LIST);
|
||||
window_close_by_class(WC_INSTALL_TRACK);
|
||||
window_close_by_class(WC_PEEP);
|
||||
window_close_by_class(WC_RIDE);
|
||||
window_close_by_class(WC_RIDE_CONSTRUCTION);
|
||||
window_close_by_class(WC_RIDE_LIST);
|
||||
window_close_by_class(WC_SCENERY);
|
||||
window_close_by_class(WC_STAFF);
|
||||
window_close_by_class(WC_TRACK_DELETE_PROMPT);
|
||||
window_close_by_class(WC_TRACK_DESIGN_LIST);
|
||||
window_close_by_class(WC_TRACK_DESIGN_PLACE);
|
||||
}
|
||||
|
||||
void PrepareParkForPlayback()
|
||||
{
|
||||
auto windowManager = GetContext()->GetUiContext()->GetWindowManager();
|
||||
windowManager->SetMainView(gSavedView, gSavedViewZoom, gSavedViewRotation);
|
||||
ResetEntitySpatialIndices();
|
||||
reset_all_sprite_quadrant_placements();
|
||||
auto intent = Intent(INTENT_ACTION_REFRESH_NEW_RIDES);
|
||||
context_broadcast_intent(&intent);
|
||||
scenery_set_default_placement_configuration();
|
||||
News::InitQueue();
|
||||
load_palette();
|
||||
gScreenAge = 0;
|
||||
gGamePaused = false;
|
||||
gGameSpeed = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fixes the view location for when the game window has changed size.
|
||||
*/
|
||||
void FixViewLocation()
|
||||
{
|
||||
rct_window* w = window_get_main();
|
||||
if (w != nullptr && w->viewport_smart_follow_sprite.IsNull())
|
||||
{
|
||||
gLoadKeepWindowsOpen = true;
|
||||
CloseParkSpecificWindows();
|
||||
context_load_park_from_stream(stream);
|
||||
}
|
||||
else
|
||||
{
|
||||
bool isScenario = ParkImporter::ExtensionIsScenario(hintPath);
|
||||
auto parkImporter = ParkImporter::Create(hintPath);
|
||||
auto result = parkImporter->LoadFromStream(stream, isScenario);
|
||||
|
||||
auto& objectManager = GetContext()->GetObjectManager();
|
||||
objectManager.LoadObjects(result.RequiredObjects);
|
||||
|
||||
parkImporter->Import();
|
||||
}
|
||||
PrepareParkForPlayback();
|
||||
success = true;
|
||||
}
|
||||
catch (const std::exception&)
|
||||
{
|
||||
Console::Error::WriteLine("Unable to load park: %s", hintPath.c_str());
|
||||
}
|
||||
gLoadKeepWindowsOpen = false;
|
||||
return success;
|
||||
}
|
||||
|
||||
void CloseParkSpecificWindows()
|
||||
{
|
||||
window_close_by_class(WC_CONSTRUCT_RIDE);
|
||||
window_close_by_class(WC_DEMOLISH_RIDE_PROMPT);
|
||||
window_close_by_class(WC_EDITOR_INVENTION_LIST_DRAG);
|
||||
window_close_by_class(WC_EDITOR_INVENTION_LIST);
|
||||
window_close_by_class(WC_EDITOR_OBJECT_SELECTION);
|
||||
window_close_by_class(WC_EDITOR_OBJECTIVE_OPTIONS);
|
||||
window_close_by_class(WC_EDITOR_SCENARIO_OPTIONS);
|
||||
window_close_by_class(WC_FINANCES);
|
||||
window_close_by_class(WC_FIRE_PROMPT);
|
||||
window_close_by_class(WC_GUEST_LIST);
|
||||
window_close_by_class(WC_INSTALL_TRACK);
|
||||
window_close_by_class(WC_PEEP);
|
||||
window_close_by_class(WC_RIDE);
|
||||
window_close_by_class(WC_RIDE_CONSTRUCTION);
|
||||
window_close_by_class(WC_RIDE_LIST);
|
||||
window_close_by_class(WC_SCENERY);
|
||||
window_close_by_class(WC_STAFF);
|
||||
window_close_by_class(WC_TRACK_DELETE_PROMPT);
|
||||
window_close_by_class(WC_TRACK_DESIGN_LIST);
|
||||
window_close_by_class(WC_TRACK_DESIGN_PLACE);
|
||||
}
|
||||
|
||||
void PrepareParkForPlayback()
|
||||
{
|
||||
auto windowManager = GetContext()->GetUiContext()->GetWindowManager();
|
||||
windowManager->SetMainView(gSavedView, gSavedViewZoom, gSavedViewRotation);
|
||||
ResetEntitySpatialIndices();
|
||||
reset_all_sprite_quadrant_placements();
|
||||
auto intent = Intent(INTENT_ACTION_REFRESH_NEW_RIDES);
|
||||
context_broadcast_intent(&intent);
|
||||
scenery_set_default_placement_configuration();
|
||||
News::InitQueue();
|
||||
load_palette();
|
||||
gScreenAge = 0;
|
||||
gGamePaused = false;
|
||||
gGameSpeed = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the map location to the given (big) coordinates. Z is automatic.
|
||||
* @param loc X and Y position in big coordinates.
|
||||
*/
|
||||
void SetViewLocation(const CoordsXY& loc)
|
||||
{
|
||||
// Update viewport
|
||||
rct_window* w = window_get_main();
|
||||
if (w != nullptr)
|
||||
{
|
||||
int32_t z = tile_element_height(loc);
|
||||
|
||||
// Prevent scroll adjustment due to window placement when in-game
|
||||
auto oldScreenFlags = gScreenFlags;
|
||||
gScreenFlags = SCREEN_FLAGS_TITLE_DEMO;
|
||||
w->SetLocation({ loc, z });
|
||||
gScreenFlags = oldScreenFlags;
|
||||
|
||||
viewport_update_position(w);
|
||||
|
||||
// Save known tile position in case of window resize
|
||||
_lastScreenWidth = w->width;
|
||||
_lastScreenHeight = w->height;
|
||||
_viewCentreLocation = loc;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fixes the view location for when the game window has changed size.
|
||||
*/
|
||||
void FixViewLocation()
|
||||
{
|
||||
rct_window* w = window_get_main();
|
||||
if (w != nullptr && w->viewport_smart_follow_sprite.IsNull())
|
||||
{
|
||||
if (w->width != _lastScreenWidth || w->height != _lastScreenHeight)
|
||||
{
|
||||
SetViewLocation(_viewCentreLocation);
|
||||
if (w->width != _lastScreenWidth || w->height != _lastScreenHeight)
|
||||
{
|
||||
// SetViewLocation(_viewCentreLocation);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
std::unique_ptr<ITitleSequencePlayer> CreateTitleSequencePlayer(GameState& gameState)
|
||||
{
|
||||
return std::make_unique<TitleSequencePlayer>(gameState);
|
||||
}
|
||||
std::unique_ptr<ITitleSequencePlayer> CreateTitleSequencePlayer(GameState& gameState)
|
||||
{
|
||||
return std::make_unique<TitleSequencePlayer>(gameState);
|
||||
}
|
||||
} // namespace OpenRCT2::Title
|
||||
|
||||
@@ -18,6 +18,9 @@ struct IScenarioRepository;
|
||||
namespace OpenRCT2
|
||||
{
|
||||
class GameState;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::unique_ptr<ITitleSequencePlayer> CreateTitleSequencePlayer(OpenRCT2::GameState& gameState);
|
||||
namespace Title
|
||||
{
|
||||
[[nodiscard]] std::unique_ptr<ITitleSequencePlayer> CreateTitleSequencePlayer(GameState& gameState);
|
||||
} // namespace Title
|
||||
} // namespace OpenRCT2
|
||||
|
||||
@@ -13,8 +13,7 @@ namespace OpenRCT2::Title
|
||||
{
|
||||
int16_t LoadParkCommand::operator()(int16_t timer)
|
||||
{
|
||||
// TODO: Load park
|
||||
|
||||
// Park loading is currently handled by the title sequence player
|
||||
return 0;
|
||||
}
|
||||
} // namespace OpenRCT2::Title
|
||||
|
||||
@@ -13,8 +13,7 @@ namespace OpenRCT2::Title
|
||||
{
|
||||
int16_t LoadScenarioCommand::operator()(int16_t timer)
|
||||
{
|
||||
// TODO: Load scenario
|
||||
|
||||
// Scenario loading is currently handled by the title sequence player
|
||||
return 0;
|
||||
}
|
||||
} // namespace OpenRCT2::Title
|
||||
|
||||
@@ -9,11 +9,20 @@
|
||||
|
||||
#include "RotateView.h"
|
||||
|
||||
#include "../../interface/Window.h"
|
||||
|
||||
namespace OpenRCT2::Title
|
||||
{
|
||||
int16_t RotateViewCommand::operator()(int16_t timer)
|
||||
{
|
||||
// TODO: Rotate the view X times
|
||||
rct_window* w = window_get_main();
|
||||
if (w != nullptr)
|
||||
{
|
||||
for (uint_fast8_t i = 0; i < Rotations; i++)
|
||||
{
|
||||
window_rotate_camera(w, 1);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -9,11 +9,29 @@
|
||||
|
||||
#include "SetLocation.h"
|
||||
|
||||
#include "../../OpenRCT2.h"
|
||||
#include "../../interface/Window.h"
|
||||
#include "../../interface/Window_internal.h"
|
||||
#include "../../world/Map.h"
|
||||
|
||||
namespace OpenRCT2::Title
|
||||
{
|
||||
int16_t SetLocationCommand::operator()(int16_t timer)
|
||||
{
|
||||
// TODO: Update view location
|
||||
rct_window* w = window_get_main();
|
||||
if (w != nullptr)
|
||||
{
|
||||
auto loc = TileCoordsXY(Location.X, Location.Y).ToCoordsXY().ToTileCentre();
|
||||
int32_t z = tile_element_height(loc);
|
||||
|
||||
// Prevent scroll adjustment due to window placement when in-game
|
||||
auto oldScreenFlags = gScreenFlags;
|
||||
gScreenFlags = SCREEN_FLAGS_TITLE_DEMO;
|
||||
w->SetLocation({ loc, z });
|
||||
gScreenFlags = oldScreenFlags;
|
||||
|
||||
viewport_update_position(w);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -9,11 +9,15 @@
|
||||
|
||||
#include "SetSpeed.h"
|
||||
|
||||
#include "../../Game.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace OpenRCT2::Title
|
||||
{
|
||||
int16_t SetSpeedCommand::operator()(int16_t timer)
|
||||
{
|
||||
// TODO: Update current zoom level
|
||||
gGameSpeed = std::clamp<uint8_t>(Speed, 1, 4);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -9,11 +9,18 @@
|
||||
|
||||
#include "SetZoom.h"
|
||||
|
||||
#include "../../interface/Window.h"
|
||||
#include "../../interface/ZoomLevel.h"
|
||||
|
||||
namespace OpenRCT2::Title
|
||||
{
|
||||
int16_t SetZoomCommand::operator()(int16_t timer)
|
||||
{
|
||||
// TODO: Update current zoom level
|
||||
rct_window* w = window_get_main();
|
||||
if (w != nullptr)
|
||||
{
|
||||
window_zoom_set(w, ZoomLevel{ static_cast<int8_t>(Zoom) }, false);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -9,10 +9,15 @@
|
||||
|
||||
#include "Wait.h"
|
||||
|
||||
#include "../../Context.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace OpenRCT2::Title
|
||||
{
|
||||
int16_t WaitCommand::operator()(int16_t timer)
|
||||
{
|
||||
return Milliseconds;
|
||||
// Return number of game ticks this wait command lasts
|
||||
return std::max<int16_t>(1, GAME_UPDATE_FPS * Milliseconds / 1000);
|
||||
}
|
||||
} // namespace OpenRCT2::Title
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -103,7 +103,7 @@ namespace TitleSequenceManager
|
||||
auto newPath = Path::Combine(Path::GetDirectory(oldPath), newName);
|
||||
if (item->IsZip)
|
||||
{
|
||||
newPath += TITLE_SEQUENCE_EXTENSION;
|
||||
newPath += OpenRCT2::Title::TITLE_SEQUENCE_EXTENSION;
|
||||
File::Move(oldPath, newPath);
|
||||
}
|
||||
else
|
||||
@@ -138,7 +138,7 @@ namespace TitleSequenceManager
|
||||
|
||||
size_t CreateItem(const utf8* name)
|
||||
{
|
||||
auto seq = CreateTitleSequence();
|
||||
auto seq = OpenRCT2::Title::CreateTitleSequence();
|
||||
seq->Name = name;
|
||||
seq->Path = GetNewTitleSequencePath(seq->Name, true);
|
||||
seq->IsZip = true;
|
||||
@@ -159,7 +159,7 @@ namespace TitleSequenceManager
|
||||
auto path = Path::Combine(GetUserSequencesPath(), name);
|
||||
if (isZip)
|
||||
{
|
||||
path += TITLE_SEQUENCE_EXTENSION;
|
||||
path += OpenRCT2::Title::TITLE_SEQUENCE_EXTENSION;
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user