mirror of https://github.com/OpenRCT2/OpenRCT2.git
Merge pull request #17426 from Broxzier/refactor/variadic-title-commands
This commit is contained in:
commit
e39fd9226f
|
@ -710,7 +710,7 @@ public:
|
||||||
{
|
{
|
||||||
auto context = GetContext();
|
auto context = GetContext();
|
||||||
auto gameState = context->GetGameState();
|
auto gameState = context->GetGameState();
|
||||||
_titleSequencePlayer = CreateTitleSequencePlayer(*gameState);
|
_titleSequencePlayer = OpenRCT2::Title::CreateTitleSequencePlayer(*gameState);
|
||||||
}
|
}
|
||||||
return _titleSequencePlayer.get();
|
return _titleSequencePlayer.get();
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,20 +24,39 @@
|
||||||
# include <openrct2/title/TitleSequence.h>
|
# include <openrct2/title/TitleSequence.h>
|
||||||
# include <openrct2/title/TitleSequenceManager.h>
|
# include <openrct2/title/TitleSequenceManager.h>
|
||||||
# include <openrct2/title/TitleSequencePlayer.h>
|
# include <openrct2/title/TitleSequencePlayer.h>
|
||||||
|
# include <type_traits>
|
||||||
|
# include <variant>
|
||||||
|
|
||||||
namespace OpenRCT2::Scripting
|
namespace OpenRCT2::Scripting
|
||||||
{
|
{
|
||||||
|
enum class TitleScript : uint8_t
|
||||||
|
{
|
||||||
|
Undefined = 0xFF,
|
||||||
|
Wait = 0,
|
||||||
|
Location,
|
||||||
|
Rotate,
|
||||||
|
Zoom,
|
||||||
|
Follow,
|
||||||
|
Restart,
|
||||||
|
Load,
|
||||||
|
End,
|
||||||
|
Speed,
|
||||||
|
Loop,
|
||||||
|
EndLoop,
|
||||||
|
LoadSc,
|
||||||
|
};
|
||||||
|
|
||||||
static const DukEnumMap<TitleScript> TitleScriptMap({
|
static const DukEnumMap<TitleScript> TitleScriptMap({
|
||||||
{ "load", TitleScript::Load },
|
{ OpenRCT2::Title::LoadParkCommand::ScriptingName, TitleScript::Load },
|
||||||
{ "location", TitleScript::Location },
|
{ OpenRCT2::Title::SetLocationCommand::ScriptingName, TitleScript::Location },
|
||||||
{ "rotate", TitleScript::Rotate },
|
{ OpenRCT2::Title::RotateViewCommand::ScriptingName, TitleScript::Rotate },
|
||||||
{ "zoom", TitleScript::Zoom },
|
{ OpenRCT2::Title::SetZoomCommand::ScriptingName, TitleScript::Zoom },
|
||||||
{ "follow", TitleScript::Follow },
|
{ OpenRCT2::Title::FollowEntityCommand::ScriptingName, TitleScript::Follow },
|
||||||
{ "speed", TitleScript::Speed },
|
{ OpenRCT2::Title::SetSpeedCommand::ScriptingName, TitleScript::Speed },
|
||||||
{ "wait", TitleScript::Wait },
|
{ OpenRCT2::Title::WaitCommand::ScriptingName, TitleScript::Wait },
|
||||||
{ "loadsc", TitleScript::LoadSc },
|
{ OpenRCT2::Title::LoadScenarioCommand::ScriptingName, TitleScript::LoadSc },
|
||||||
{ "restart", TitleScript::Restart },
|
{ OpenRCT2::Title::RestartCommand::ScriptingName, TitleScript::Restart },
|
||||||
{ "end", TitleScript::End },
|
{ OpenRCT2::Title::EndCommand::ScriptingName, TitleScript::End },
|
||||||
});
|
});
|
||||||
|
|
||||||
template<> DukValue ToDuk(duk_context* ctx, const TitleScript& value)
|
template<> DukValue ToDuk(duk_context* ctx, const TitleScript& value)
|
||||||
|
@ -45,43 +64,52 @@ namespace OpenRCT2::Scripting
|
||||||
return ToDuk(ctx, TitleScriptMap[value]);
|
return ToDuk(ctx, TitleScriptMap[value]);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<> DukValue ToDuk(duk_context* ctx, const TitleCommand& value)
|
template<> DukValue ToDuk(duk_context* ctx, const OpenRCT2::Title::TitleCommand& value)
|
||||||
{
|
{
|
||||||
|
using namespace OpenRCT2::Title;
|
||||||
DukObject obj(ctx);
|
DukObject obj(ctx);
|
||||||
obj.Set("type", ToDuk(ctx, value.Type));
|
std::visit(
|
||||||
switch (value.Type)
|
[&obj](auto&& command) {
|
||||||
{
|
using T = std::decay_t<decltype(command)>;
|
||||||
case TitleScript::Load:
|
obj.Set("type", T::ScriptingName);
|
||||||
obj.Set("index", value.SaveIndex);
|
if constexpr (std::is_same_v<T, LoadParkCommand>)
|
||||||
break;
|
{
|
||||||
case TitleScript::Location:
|
obj.Set("index", command.SaveIndex);
|
||||||
obj.Set("x", value.Location.X);
|
}
|
||||||
obj.Set("y", value.Location.Y);
|
else if constexpr (std::is_same_v<T, SetLocationCommand>)
|
||||||
break;
|
{
|
||||||
case TitleScript::Rotate:
|
obj.Set("x", command.Location.X);
|
||||||
obj.Set("rotations", value.Rotations);
|
obj.Set("y", command.Location.Y);
|
||||||
break;
|
}
|
||||||
case TitleScript::Zoom:
|
else if constexpr (std::is_same_v<T, RotateViewCommand>)
|
||||||
obj.Set("zoom", value.Zoom);
|
{
|
||||||
break;
|
obj.Set("rotations", command.Rotations);
|
||||||
case TitleScript::Follow:
|
}
|
||||||
if (value.Follow.SpriteIndex.IsNull())
|
else if constexpr (std::is_same_v<T, SetZoomCommand>)
|
||||||
obj.Set("id", nullptr);
|
{
|
||||||
else
|
obj.Set("zoom", command.Zoom);
|
||||||
obj.Set("id", value.Follow.SpriteIndex.ToUnderlying());
|
}
|
||||||
break;
|
else if constexpr (std::is_same_v<T, FollowEntityCommand>)
|
||||||
case TitleScript::Speed:
|
{
|
||||||
obj.Set("speed", value.Speed);
|
if (command.Follow.SpriteIndex.IsNull())
|
||||||
break;
|
obj.Set("id", nullptr);
|
||||||
case TitleScript::Wait:
|
else
|
||||||
obj.Set("duration", value.Milliseconds);
|
obj.Set("id", command.Follow.SpriteIndex.ToUnderlying());
|
||||||
break;
|
}
|
||||||
case TitleScript::LoadSc:
|
else if constexpr (std::is_same_v<T, SetSpeedCommand>)
|
||||||
obj.Set("scenario", String::ToStringView(value.Scenario, sizeof(value.Scenario)));
|
{
|
||||||
break;
|
obj.Set("speed", command.Speed);
|
||||||
default:
|
}
|
||||||
break;
|
else if constexpr (std::is_same_v<T, WaitCommand>)
|
||||||
}
|
{
|
||||||
|
obj.Set("duration", command.Milliseconds);
|
||||||
|
}
|
||||||
|
else if constexpr (std::is_same_v<T, LoadScenarioCommand>)
|
||||||
|
{
|
||||||
|
obj.Set("scenario", String::ToStringView(command.Scenario, sizeof(command.Scenario)));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
value);
|
||||||
return obj.Take();
|
return obj.Take();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,47 +120,60 @@ namespace OpenRCT2::Scripting
|
||||||
throw DukException() << "Invalid title command id";
|
throw DukException() << "Invalid title command id";
|
||||||
}
|
}
|
||||||
|
|
||||||
template<> TitleCommand FromDuk(const DukValue& value)
|
template<> OpenRCT2::Title::TitleCommand FromDuk(const DukValue& value)
|
||||||
{
|
{
|
||||||
|
using namespace OpenRCT2::Title;
|
||||||
auto type = FromDuk<TitleScript>(value["type"]);
|
auto type = FromDuk<TitleScript>(value["type"]);
|
||||||
TitleCommand command{};
|
TitleCommand command{};
|
||||||
command.Type = type;
|
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case TitleScript::Load:
|
case TitleScript::Load:
|
||||||
command.SaveIndex = value["index"].as_int();
|
command = LoadParkCommand{ static_cast<uint8_t>(value["index"].as_int()) };
|
||||||
break;
|
break;
|
||||||
case TitleScript::Location:
|
case TitleScript::Location:
|
||||||
command.Location.X = value["x"].as_int();
|
command = SetLocationCommand{
|
||||||
command.Location.Y = value["y"].as_int();
|
static_cast<uint8_t>(value["x"].as_int()),
|
||||||
|
static_cast<uint8_t>(value["y"].as_int()),
|
||||||
|
};
|
||||||
break;
|
break;
|
||||||
case TitleScript::Rotate:
|
case TitleScript::Rotate:
|
||||||
command.Rotations = value["rotations"].as_int();
|
command = RotateViewCommand{ static_cast<uint8_t>(value["rotations"].as_int()) };
|
||||||
break;
|
break;
|
||||||
case TitleScript::Zoom:
|
case TitleScript::Zoom:
|
||||||
command.Zoom = value["zoom"].as_int();
|
command = SetZoomCommand{ static_cast<uint8_t>(value["zoom"].as_int()) };
|
||||||
break;
|
break;
|
||||||
case TitleScript::Follow:
|
case TitleScript::Follow:
|
||||||
{
|
{
|
||||||
auto dukId = value["id"];
|
auto dukId = value["id"];
|
||||||
if (dukId.type() == DukValue::Type::NUMBER)
|
if (dukId.type() == DukValue::Type::NUMBER)
|
||||||
{
|
{
|
||||||
command.Follow.SpriteIndex = EntityId::FromUnderlying(dukId.as_int());
|
command = FollowEntityCommand{ EntityId::FromUnderlying(dukId.as_int()) };
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
command.Follow.SpriteIndex = EntityId::GetNull();
|
command = FollowEntityCommand{ EntityId::GetNull() };
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case TitleScript::Speed:
|
case TitleScript::Speed:
|
||||||
command.Speed = value["speed"].as_int();
|
command = SetSpeedCommand{ static_cast<uint8_t>(value["speed"].as_int()) };
|
||||||
break;
|
break;
|
||||||
case TitleScript::Wait:
|
case TitleScript::Wait:
|
||||||
command.Milliseconds = value["duration"].as_int();
|
command = WaitCommand{ static_cast<uint16_t>(value["duration"].as_int()) };
|
||||||
break;
|
break;
|
||||||
case TitleScript::LoadSc:
|
case TitleScript::LoadSc:
|
||||||
String::Set(command.Scenario, sizeof(command.Scenario), value["scenario"].as_c_string());
|
{
|
||||||
|
auto loadScenarioCommand = LoadScenarioCommand{};
|
||||||
|
String::Set(
|
||||||
|
loadScenarioCommand.Scenario, sizeof(loadScenarioCommand.Scenario), value["scenario"].as_c_string());
|
||||||
|
command = loadScenarioCommand;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case TitleScript::Restart:
|
||||||
|
command = RestartCommand{};
|
||||||
|
break;
|
||||||
|
case TitleScript::End:
|
||||||
|
command = EndCommand{};
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
@ -164,7 +205,7 @@ namespace OpenRCT2::Scripting
|
||||||
if (value == _fileName)
|
if (value == _fileName)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto seq = LoadTitleSequence(_titleSequencePath);
|
auto seq = OpenRCT2::Title::LoadTitleSequence(_titleSequencePath);
|
||||||
if (seq != nullptr)
|
if (seq != nullptr)
|
||||||
{
|
{
|
||||||
// Check if name already in use
|
// Check if name already in use
|
||||||
|
@ -183,27 +224,27 @@ namespace OpenRCT2::Scripting
|
||||||
|
|
||||||
void delete_()
|
void delete_()
|
||||||
{
|
{
|
||||||
auto seq = LoadTitleSequence(_titleSequencePath);
|
auto seq = OpenRCT2::Title::LoadTitleSequence(_titleSequencePath);
|
||||||
if (seq != nullptr)
|
if (seq != nullptr)
|
||||||
{
|
{
|
||||||
auto index = GetIndex(*seq, _fileName);
|
auto index = GetIndex(*seq, _fileName);
|
||||||
if (index)
|
if (index)
|
||||||
{
|
{
|
||||||
TitleSequenceRemovePark(*seq, *index);
|
OpenRCT2::Title::TitleSequenceRemovePark(*seq, *index);
|
||||||
TitleSequenceSave(*seq);
|
OpenRCT2::Title::TitleSequenceSave(*seq);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void load()
|
void load()
|
||||||
{
|
{
|
||||||
auto seq = LoadTitleSequence(_titleSequencePath);
|
auto seq = OpenRCT2::Title::LoadTitleSequence(_titleSequencePath);
|
||||||
if (seq != nullptr)
|
if (seq != nullptr)
|
||||||
{
|
{
|
||||||
auto index = GetIndex(*seq, _fileName);
|
auto index = GetIndex(*seq, _fileName);
|
||||||
if (index)
|
if (index)
|
||||||
{
|
{
|
||||||
auto handle = TitleSequenceGetParkHandle(*seq, *index);
|
auto handle = OpenRCT2::Title::TitleSequenceGetParkHandle(*seq, *index);
|
||||||
auto isScenario = ParkImporter::ExtensionIsScenario(handle->HintPath);
|
auto isScenario = ParkImporter::ExtensionIsScenario(handle->HintPath);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -246,7 +287,7 @@ namespace OpenRCT2::Scripting
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static std::optional<size_t> GetIndex(const TitleSequence& seq, const std::string_view needle)
|
static std::optional<size_t> GetIndex(const OpenRCT2::Title::TitleSequence& seq, const std::string_view needle)
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < seq.Saves.size(); i++)
|
for (size_t i = 0; i < seq.Saves.size(); i++)
|
||||||
{
|
{
|
||||||
|
@ -327,7 +368,7 @@ namespace OpenRCT2::Scripting
|
||||||
std::vector<std::shared_ptr<ScTitleSequencePark>> parks_get() const
|
std::vector<std::shared_ptr<ScTitleSequencePark>> parks_get() const
|
||||||
{
|
{
|
||||||
std::vector<std::shared_ptr<ScTitleSequencePark>> result;
|
std::vector<std::shared_ptr<ScTitleSequencePark>> result;
|
||||||
auto titleSeq = LoadTitleSequence(_path);
|
auto titleSeq = OpenRCT2::Title::LoadTitleSequence(_path);
|
||||||
if (titleSeq != nullptr)
|
if (titleSeq != nullptr)
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < titleSeq->Saves.size(); i++)
|
for (size_t i = 0; i < titleSeq->Saves.size(); i++)
|
||||||
|
@ -344,7 +385,7 @@ namespace OpenRCT2::Scripting
|
||||||
auto ctx = scriptEngine.GetContext();
|
auto ctx = scriptEngine.GetContext();
|
||||||
|
|
||||||
std::vector<DukValue> result;
|
std::vector<DukValue> result;
|
||||||
auto titleSeq = LoadTitleSequence(_path);
|
auto titleSeq = OpenRCT2::Title::LoadTitleSequence(_path);
|
||||||
if (titleSeq != nullptr)
|
if (titleSeq != nullptr)
|
||||||
{
|
{
|
||||||
for (const auto& command : titleSeq->Commands)
|
for (const auto& command : titleSeq->Commands)
|
||||||
|
@ -357,23 +398,23 @@ namespace OpenRCT2::Scripting
|
||||||
|
|
||||||
void commands_set(const std::vector<DukValue>& value)
|
void commands_set(const std::vector<DukValue>& value)
|
||||||
{
|
{
|
||||||
std::vector<TitleCommand> commands;
|
std::vector<OpenRCT2::Title::TitleCommand> commands;
|
||||||
for (const auto& v : value)
|
for (const auto& v : value)
|
||||||
{
|
{
|
||||||
auto command = FromDuk<TitleCommand>(v);
|
auto command = FromDuk<OpenRCT2::Title::TitleCommand>(v);
|
||||||
commands.push_back(std::move(command));
|
commands.push_back(std::move(command));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto titleSeq = LoadTitleSequence(_path);
|
auto titleSeq = OpenRCT2::Title::LoadTitleSequence(_path);
|
||||||
titleSeq->Commands = commands;
|
titleSeq->Commands = commands;
|
||||||
TitleSequenceSave(*titleSeq);
|
OpenRCT2::Title::TitleSequenceSave(*titleSeq);
|
||||||
}
|
}
|
||||||
|
|
||||||
void addPark(const std::string& path, const std::string& fileName)
|
void addPark(const std::string& path, const std::string& fileName)
|
||||||
{
|
{
|
||||||
auto titleSeq = LoadTitleSequence(_path);
|
auto titleSeq = OpenRCT2::Title::LoadTitleSequence(_path);
|
||||||
TitleSequenceAddPark(*titleSeq, path.c_str(), fileName.c_str());
|
OpenRCT2::Title::TitleSequenceAddPark(*titleSeq, path.c_str(), fileName.c_str());
|
||||||
TitleSequenceSave(*titleSeq);
|
OpenRCT2::Title::TitleSequenceSave(*titleSeq);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<ScTitleSequence> clone(const std::string& name) const
|
std::shared_ptr<ScTitleSequence> clone(const std::string& name) const
|
||||||
|
|
|
@ -39,489 +39,377 @@
|
||||||
#include <openrct2/windows/Intent.h>
|
#include <openrct2/windows/Intent.h>
|
||||||
#include <openrct2/world/Map.h>
|
#include <openrct2/world/Map.h>
|
||||||
#include <openrct2/world/Scenery.h>
|
#include <openrct2/world/Scenery.h>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
using namespace OpenRCT2;
|
namespace OpenRCT2::Title
|
||||||
|
|
||||||
class TitleSequencePlayer final : public ITitleSequencePlayer
|
|
||||||
{
|
{
|
||||||
private:
|
class TitleSequencePlayer final : public ITitleSequencePlayer
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
}
|
private:
|
||||||
|
GameState& _gameState;
|
||||||
|
|
||||||
~TitleSequencePlayer() override
|
std::unique_ptr<TitleSequence> _sequence;
|
||||||
{
|
int32_t _position = 0;
|
||||||
Eject();
|
int32_t _waitCounter = 0;
|
||||||
}
|
|
||||||
|
|
||||||
int32_t GetCurrentPosition() const override
|
int32_t _previousWindowWidth = 0;
|
||||||
{
|
int32_t _previousWindowHeight = 0;
|
||||||
return _position;
|
ScreenCoordsXY _previousViewPosition = {};
|
||||||
}
|
|
||||||
|
|
||||||
void Eject() override
|
public:
|
||||||
{
|
explicit TitleSequencePlayer(GameState& gameState)
|
||||||
_sequence = nullptr;
|
: _gameState(gameState)
|
||||||
}
|
|
||||||
|
|
||||||
bool Begin(size_t titleSequenceId) override
|
|
||||||
{
|
|
||||||
size_t numSequences = TitleSequenceManager::GetCount();
|
|
||||||
if (titleSequenceId >= numSequences)
|
|
||||||
{
|
{
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto seqItem = TitleSequenceManager::GetItem(titleSequenceId);
|
~TitleSequencePlayer() override
|
||||||
auto sequence = LoadTitleSequence(seqItem->Path);
|
|
||||||
if (sequence == nullptr)
|
|
||||||
{
|
{
|
||||||
return false;
|
Eject();
|
||||||
}
|
}
|
||||||
|
|
||||||
Eject();
|
int32_t GetCurrentPosition() const override
|
||||||
_sequence = std::move(sequence);
|
|
||||||
|
|
||||||
Reset();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Update() override
|
|
||||||
{
|
|
||||||
int32_t entryPosition = _position;
|
|
||||||
FixViewLocation();
|
|
||||||
|
|
||||||
if (_sequence == nullptr)
|
|
||||||
{
|
{
|
||||||
SetViewLocation(TileCoordsXY(75, 75).ToCoordsXY());
|
return _position;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that position is valid
|
void Eject() override
|
||||||
if (_position >= static_cast<int32_t>(_sequence->Commands.size()))
|
|
||||||
{
|
{
|
||||||
_position = 0;
|
_sequence = nullptr;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't execute next command until we are done with the current wait command
|
bool Begin(size_t titleSequenceId) override
|
||||||
if (_waitCounter != 0)
|
|
||||||
{
|
{
|
||||||
_waitCounter--;
|
StoreCurrentViewLocation();
|
||||||
if (_waitCounter == 0)
|
|
||||||
|
size_t numSequences = TitleSequenceManager::GetCount();
|
||||||
|
if (titleSequenceId >= numSequences)
|
||||||
{
|
{
|
||||||
const auto& command = _sequence->Commands[_position];
|
return false;
|
||||||
if (command.Type == TitleScript::Wait)
|
|
||||||
{
|
|
||||||
IncrementPosition();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
||||||
{
|
{
|
||||||
|
RestoreViewLocationIfResized();
|
||||||
|
|
||||||
|
if (_sequence == nullptr)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run commands in order, until we reach one that is not instantly done
|
||||||
|
int32_t entryPosition = _position;
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
const auto& command = _sequence->Commands[_position];
|
auto& currentCommand = _sequence->Commands[_position];
|
||||||
if (ExecuteCommand(command))
|
try
|
||||||
{
|
{
|
||||||
if (command.Type == TitleScript::Wait)
|
int framesToWait = std::visit([&](auto& command) { return command(_waitCounter); }, currentCommand);
|
||||||
|
if (framesToWait > _waitCounter)
|
||||||
{
|
{
|
||||||
|
_waitCounter++;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
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.");
|
auto& scenarioName = std::get<LoadScenarioCommand>(currentCommand).Scenario;
|
||||||
Console::Error::WriteLine(" A wait command may be missing.");
|
bool loadSuccess = false;
|
||||||
return 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)
|
const char* commandName = std::visit(
|
||||||
{
|
[](auto&& command) { return std::decay_t<decltype(command)>::Name; }, currentCommand);
|
||||||
Console::Error::WriteLine("Unable to load any parks from %s.", _sequence->Name.c_str());
|
Console::Error::WriteLine("%s (command %i) failed with error: %s", commandName, _position, e.what());
|
||||||
return false;
|
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
|
// Store current window size and screen position in case the window resizes and the main focus changes
|
||||||
{
|
StoreCurrentViewLocation();
|
||||||
_position = 0;
|
|
||||||
_waitCounter = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Seek(int32_t targetPosition) override
|
return true;
|
||||||
{
|
|
||||||
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)
|
void Reset() override
|
||||||
{
|
|
||||||
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()))
|
|
||||||
{
|
{
|
||||||
_position = 0;
|
_position = 0;
|
||||||
|
_waitCounter = 0;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
bool SkipToNextLoadCommand()
|
void Seek(int32_t targetPosition) override
|
||||||
{
|
|
||||||
int32_t entryPosition = _position;
|
|
||||||
const TitleCommand* command;
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
IncrementPosition();
|
if (targetPosition < 0 || targetPosition >= static_cast<int32_t>(_sequence->Commands.size()))
|
||||||
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:
|
|
||||||
{
|
{
|
||||||
auto loc = TileCoordsXY(command.Location.X, command.Location.Y).ToCoordsXY().ToTileCentre();
|
throw std::runtime_error("Invalid position.");
|
||||||
SetViewLocation(loc);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
case TitleScript::Undefined:
|
if (_position >= targetPosition)
|
||||||
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:
|
|
||||||
Reset();
|
Reset();
|
||||||
break;
|
}
|
||||||
case TitleScript::Load:
|
|
||||||
|
if (std::holds_alternative<RestartCommand>(_sequence->Commands[targetPosition]))
|
||||||
{
|
{
|
||||||
bool loadSuccess = false;
|
targetPosition = 0;
|
||||||
uint8_t saveIndex = command.SaveIndex;
|
}
|
||||||
auto parkHandle = TitleSequenceGetParkHandle(*_sequence, saveIndex);
|
|
||||||
if (parkHandle != nullptr)
|
// 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();
|
// Break if we have a new load command or if we're already in the range of the correct load command
|
||||||
loadSuccess = LoadParkFromStream(parkHandle->Stream.get(), parkHandle->HintPath);
|
_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
|
else
|
||||||
{
|
{
|
||||||
if (_sequence->Saves.size() > saveIndex)
|
break;
|
||||||
{
|
|
||||||
const auto& path = _sequence->Saves[saveIndex];
|
|
||||||
Console::Error::WriteLine("Failed to load: \"%s\" for the title sequence.", path.c_str());
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
case TitleScript::LoadSc:
|
|
||||||
|
gInUpdateCode = false;
|
||||||
|
|
||||||
|
_waitCounter = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void IncrementPosition()
|
||||||
|
{
|
||||||
|
_position++;
|
||||||
|
if (_position >= static_cast<int32_t>(_sequence->Commands.size()))
|
||||||
{
|
{
|
||||||
bool loadSuccess = false;
|
_position = 0;
|
||||||
auto scenario = GetScenarioRepository()->GetByInternalName(command.Scenario);
|
}
|
||||||
if (scenario != nullptr)
|
_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;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LoadParkFromFile(const utf8* path)
|
||||||
|
{
|
||||||
|
log_verbose("TitleSequencePlayer::LoadParkFromFile(%s)", path);
|
||||||
|
bool success = false;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (gPreviewingTitleSequenceInGame)
|
||||||
{
|
{
|
||||||
game_notify_map_change();
|
gLoadKeepWindowsOpen = true;
|
||||||
loadSuccess = LoadParkFromFile(scenario->path);
|
CloseParkSpecificWindows();
|
||||||
}
|
context_load_park_from_file(path);
|
||||||
if (loadSuccess)
|
|
||||||
{
|
|
||||||
game_notify_map_changed();
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Console::Error::WriteLine("Failed to load: \"%s\" for the title sequence.", command.Scenario);
|
auto parkImporter = ParkImporter::Create(path);
|
||||||
return false;
|
auto result = parkImporter->Load(path);
|
||||||
|
|
||||||
|
auto& objectManager = GetContext()->GetObjectManager();
|
||||||
|
objectManager.LoadObjects(result.RequiredObjects);
|
||||||
|
|
||||||
|
parkImporter->Import();
|
||||||
}
|
}
|
||||||
break;
|
PrepareParkForPlayback();
|
||||||
|
success = true;
|
||||||
}
|
}
|
||||||
}
|
catch (const std::exception&)
|
||||||
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++)
|
|
||||||
{
|
{
|
||||||
window_rotate_camera(w, 1);
|
Console::Error::WriteLine("Unable to load park: %s", path);
|
||||||
}
|
}
|
||||||
|
gLoadKeepWindowsOpen = false;
|
||||||
|
return success;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void FollowSprite(EntityId spriteIndex)
|
/**
|
||||||
{
|
* @param stream The stream to read the park data from.
|
||||||
rct_window* w = window_get_main();
|
* @param hintPath Hint path, the extension is grabbed to determine what importer to use.
|
||||||
if (w != nullptr)
|
*/
|
||||||
|
bool LoadParkFromStream(OpenRCT2::IStream* stream, const std::string& hintPath)
|
||||||
{
|
{
|
||||||
window_follow_sprite(w, spriteIndex);
|
log_verbose("TitleSequencePlayer::LoadParkFromStream(%s)", hintPath.c_str());
|
||||||
}
|
bool success = false;
|
||||||
}
|
try
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
gLoadKeepWindowsOpen = true;
|
if (gPreviewingTitleSequenceInGame)
|
||||||
CloseParkSpecificWindows();
|
{
|
||||||
context_load_park_from_file(path);
|
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);
|
Console::Error::WriteLine("Unable to load park: %s", hintPath.c_str());
|
||||||
auto result = parkImporter->Load(path);
|
|
||||||
|
|
||||||
auto& objectManager = GetContext()->GetObjectManager();
|
|
||||||
objectManager.LoadObjects(result.RequiredObjects);
|
|
||||||
|
|
||||||
parkImporter->Import();
|
|
||||||
}
|
}
|
||||||
PrepareParkForPlayback();
|
gLoadKeepWindowsOpen = false;
|
||||||
success = true;
|
return success;
|
||||||
}
|
}
|
||||||
catch (const std::exception&)
|
|
||||||
{
|
|
||||||
Console::Error::WriteLine("Unable to load park: %s", path);
|
|
||||||
}
|
|
||||||
gLoadKeepWindowsOpen = false;
|
|
||||||
return success;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
void CloseParkSpecificWindows()
|
||||||
* @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
|
|
||||||
{
|
{
|
||||||
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
void StoreCurrentViewLocation()
|
||||||
|
{
|
||||||
|
rct_window* w = window_get_main();
|
||||||
|
if (w != nullptr && w->viewport_smart_follow_sprite.IsNull())
|
||||||
{
|
{
|
||||||
gLoadKeepWindowsOpen = true;
|
_previousWindowWidth = w->width;
|
||||||
CloseParkSpecificWindows();
|
_previousWindowHeight = w->height;
|
||||||
context_load_park_from_stream(stream);
|
_previousViewPosition = w->savedViewPos;
|
||||||
}
|
}
|
||||||
else
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fixes the view location for when the game window has changed size.
|
||||||
|
*/
|
||||||
|
void RestoreViewLocationIfResized()
|
||||||
|
{
|
||||||
|
rct_window* w = window_get_main();
|
||||||
|
if (w != nullptr && w->viewport_smart_follow_sprite.IsNull())
|
||||||
{
|
{
|
||||||
bool isScenario = ParkImporter::ExtensionIsScenario(hintPath);
|
if (w->width != _previousWindowWidth || w->height != _previousWindowHeight)
|
||||||
auto parkImporter = ParkImporter::Create(hintPath);
|
{
|
||||||
auto result = parkImporter->LoadFromStream(stream, isScenario);
|
w->savedViewPos.x += (_previousWindowWidth - w->width) / 2;
|
||||||
|
w->savedViewPos.y += (_previousWindowHeight - w->height) / 2;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
};
|
|
||||||
|
|
||||||
std::unique_ptr<ITitleSequencePlayer> CreateTitleSequencePlayer(GameState& gameState)
|
std::unique_ptr<ITitleSequencePlayer> CreateTitleSequencePlayer(GameState& gameState)
|
||||||
{
|
{
|
||||||
return std::make_unique<TitleSequencePlayer>(gameState);
|
return std::make_unique<TitleSequencePlayer>(gameState);
|
||||||
}
|
}
|
||||||
|
} // namespace OpenRCT2::Title
|
||||||
|
|
|
@ -18,6 +18,9 @@ struct IScenarioRepository;
|
||||||
namespace OpenRCT2
|
namespace OpenRCT2
|
||||||
{
|
{
|
||||||
class GameState;
|
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
|
||||||
|
|
|
@ -27,7 +27,6 @@ struct rct_drawpixelinfo;
|
||||||
struct rct_window;
|
struct rct_window;
|
||||||
union rct_window_event;
|
union rct_window_event;
|
||||||
struct track_design_file_ref;
|
struct track_design_file_ref;
|
||||||
struct TitleSequence;
|
|
||||||
struct TextInputSession;
|
struct TextInputSession;
|
||||||
struct scenario_index_entry;
|
struct scenario_index_entry;
|
||||||
|
|
||||||
|
|
|
@ -497,6 +497,16 @@
|
||||||
<ClInclude Include="scripting\bindings\world\ScTile.hpp" />
|
<ClInclude Include="scripting\bindings\world\ScTile.hpp" />
|
||||||
<ClInclude Include="sprites.h" />
|
<ClInclude Include="sprites.h" />
|
||||||
<ClInclude Include="System.hpp" />
|
<ClInclude Include="System.hpp" />
|
||||||
|
<ClInclude Include="title\Command\End.h" />
|
||||||
|
<ClInclude Include="title\Command\FollowEntity.h" />
|
||||||
|
<ClInclude Include="title\Command\LoadPark.h" />
|
||||||
|
<ClInclude Include="title\Command\LoadScenario.h" />
|
||||||
|
<ClInclude Include="title\Command\Restart.h" />
|
||||||
|
<ClInclude Include="title\Command\RotateView.h" />
|
||||||
|
<ClInclude Include="title\Command\SetLocation.h" />
|
||||||
|
<ClInclude Include="title\Command\SetSpeed.h" />
|
||||||
|
<ClInclude Include="title\Command\SetZoom.h" />
|
||||||
|
<ClInclude Include="title\Command\Wait.h" />
|
||||||
<ClInclude Include="title\TitleScreen.h" />
|
<ClInclude Include="title\TitleScreen.h" />
|
||||||
<ClInclude Include="title\TitleSequence.h" />
|
<ClInclude Include="title\TitleSequence.h" />
|
||||||
<ClInclude Include="title\TitleSequenceManager.h" />
|
<ClInclude Include="title\TitleSequenceManager.h" />
|
||||||
|
@ -941,6 +951,16 @@
|
||||||
<ClCompile Include="scripting\HookEngine.cpp" />
|
<ClCompile Include="scripting\HookEngine.cpp" />
|
||||||
<ClCompile Include="scripting\Plugin.cpp" />
|
<ClCompile Include="scripting\Plugin.cpp" />
|
||||||
<ClCompile Include="scripting\ScriptEngine.cpp" />
|
<ClCompile Include="scripting\ScriptEngine.cpp" />
|
||||||
|
<ClCompile Include="title\Command\End.cpp" />
|
||||||
|
<ClCompile Include="title\Command\FollowEntity.cpp" />
|
||||||
|
<ClCompile Include="title\Command\LoadPark.cpp" />
|
||||||
|
<ClCompile Include="title\Command\LoadScenario.cpp" />
|
||||||
|
<ClCompile Include="title\Command\Restart.cpp" />
|
||||||
|
<ClCompile Include="title\Command\RotateView.cpp" />
|
||||||
|
<ClCompile Include="title\Command\SetLocation.cpp" />
|
||||||
|
<ClCompile Include="title\Command\SetSpeed.cpp" />
|
||||||
|
<ClCompile Include="title\Command\SetZoom.cpp" />
|
||||||
|
<ClCompile Include="title\Command\Wait.cpp" />
|
||||||
<ClCompile Include="title\TitleScreen.cpp" />
|
<ClCompile Include="title\TitleScreen.cpp" />
|
||||||
<ClCompile Include="title\TitleSequence.cpp" />
|
<ClCompile Include="title\TitleSequence.cpp" />
|
||||||
<ClCompile Include="title\TitleSequenceManager.cpp" />
|
<ClCompile Include="title\TitleSequenceManager.cpp" />
|
||||||
|
@ -975,4 +995,4 @@
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
</Project>
|
</Project>
|
|
@ -46,7 +46,7 @@ namespace OpenRCT2
|
||||||
|
|
||||||
namespace OpenRCT2::Scripting
|
namespace OpenRCT2::Scripting
|
||||||
{
|
{
|
||||||
static constexpr int32_t OPENRCT2_PLUGIN_API_VERSION = 56;
|
static constexpr int32_t OPENRCT2_PLUGIN_API_VERSION = 57;
|
||||||
|
|
||||||
// Versions marking breaking changes.
|
// Versions marking breaking changes.
|
||||||
static constexpr int32_t API_VERSION_33_PEEP_DEPRECATION = 33;
|
static constexpr int32_t API_VERSION_33_PEEP_DEPRECATION = 33;
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* Copyright (c) 2014-2022 OpenRCT2 developers
|
||||||
|
*
|
||||||
|
* For a complete list of all authors, please refer to contributors.md
|
||||||
|
* Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
|
||||||
|
*
|
||||||
|
* OpenRCT2 is licensed under the GNU General Public License version 3.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#include "End.h"
|
||||||
|
|
||||||
|
namespace OpenRCT2::Title
|
||||||
|
{
|
||||||
|
int16_t EndCommand::operator()(int16_t timer)
|
||||||
|
{
|
||||||
|
// The end command is used as a tag, no logic required here.
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} // namespace OpenRCT2::Title
|
|
@ -0,0 +1,23 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* Copyright (c) 2014-2022 OpenRCT2 developers
|
||||||
|
*
|
||||||
|
* For a complete list of all authors, please refer to contributors.md
|
||||||
|
* Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
|
||||||
|
*
|
||||||
|
* OpenRCT2 is licensed under the GNU General Public License version 3.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace OpenRCT2::Title
|
||||||
|
{
|
||||||
|
struct EndCommand
|
||||||
|
{
|
||||||
|
static constexpr const char* Name = "End Command";
|
||||||
|
static constexpr const char* ScriptingName = "end";
|
||||||
|
|
||||||
|
int16_t operator()(int16_t timer);
|
||||||
|
};
|
||||||
|
} // namespace OpenRCT2::Title
|
|
@ -0,0 +1,26 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* Copyright (c) 2014-2022 OpenRCT2 developers
|
||||||
|
*
|
||||||
|
* For a complete list of all authors, please refer to contributors.md
|
||||||
|
* Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
|
||||||
|
*
|
||||||
|
* OpenRCT2 is licensed under the GNU General Public License version 3.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#include "FollowEntity.h"
|
||||||
|
|
||||||
|
#include "../../interface/Window.h"
|
||||||
|
|
||||||
|
namespace OpenRCT2::Title
|
||||||
|
{
|
||||||
|
int16_t FollowEntityCommand::operator()(int16_t timer)
|
||||||
|
{
|
||||||
|
auto* w = window_get_main();
|
||||||
|
if (w != nullptr)
|
||||||
|
{
|
||||||
|
window_follow_sprite(w, Follow.SpriteIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} // namespace OpenRCT2::Title
|
|
@ -0,0 +1,33 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* Copyright (c) 2014-2022 OpenRCT2 developers
|
||||||
|
*
|
||||||
|
* For a complete list of all authors, please refer to contributors.md
|
||||||
|
* Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
|
||||||
|
*
|
||||||
|
* OpenRCT2 is licensed under the GNU General Public License version 3.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../../Identifiers.h"
|
||||||
|
#include "../../core/String.hpp"
|
||||||
|
#include "../../localisation/Localisation.h"
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace OpenRCT2::Title
|
||||||
|
{
|
||||||
|
struct FollowEntityCommand
|
||||||
|
{
|
||||||
|
static constexpr const char* Name = "Follow Entity Command";
|
||||||
|
static constexpr const char* ScriptingName = "follow";
|
||||||
|
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
EntityId SpriteIndex{ EntityId::GetNull() };
|
||||||
|
utf8 SpriteName[USER_STRING_MAX_LENGTH]{};
|
||||||
|
} Follow;
|
||||||
|
|
||||||
|
int16_t operator()(int16_t timer);
|
||||||
|
};
|
||||||
|
} // namespace OpenRCT2::Title
|
|
@ -0,0 +1,19 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* Copyright (c) 2014-2022 OpenRCT2 developers
|
||||||
|
*
|
||||||
|
* For a complete list of all authors, please refer to contributors.md
|
||||||
|
* Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
|
||||||
|
*
|
||||||
|
* OpenRCT2 is licensed under the GNU General Public License version 3.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#include "LoadPark.h"
|
||||||
|
|
||||||
|
namespace OpenRCT2::Title
|
||||||
|
{
|
||||||
|
int16_t LoadParkCommand::operator()(int16_t timer)
|
||||||
|
{
|
||||||
|
// Park loading is currently handled by the title sequence player
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} // namespace OpenRCT2::Title
|
|
@ -0,0 +1,25 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* Copyright (c) 2014-2022 OpenRCT2 developers
|
||||||
|
*
|
||||||
|
* For a complete list of all authors, please refer to contributors.md
|
||||||
|
* Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
|
||||||
|
*
|
||||||
|
* OpenRCT2 is licensed under the GNU General Public License version 3.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace OpenRCT2::Title
|
||||||
|
{
|
||||||
|
struct LoadParkCommand
|
||||||
|
{
|
||||||
|
static constexpr const char* Name = "Load Park Command";
|
||||||
|
static constexpr const char* ScriptingName = "load";
|
||||||
|
|
||||||
|
uint8_t SaveIndex{};
|
||||||
|
|
||||||
|
int16_t operator()(int16_t timer);
|
||||||
|
};
|
||||||
|
} // namespace OpenRCT2::Title
|
|
@ -0,0 +1,19 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* Copyright (c) 2014-2022 OpenRCT2 developers
|
||||||
|
*
|
||||||
|
* For a complete list of all authors, please refer to contributors.md
|
||||||
|
* Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
|
||||||
|
*
|
||||||
|
* OpenRCT2 is licensed under the GNU General Public License version 3.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#include "LoadScenario.h"
|
||||||
|
|
||||||
|
namespace OpenRCT2::Title
|
||||||
|
{
|
||||||
|
int16_t LoadScenarioCommand::operator()(int16_t timer)
|
||||||
|
{
|
||||||
|
// Scenario loading is currently handled by the title sequence player
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} // namespace OpenRCT2::Title
|
|
@ -0,0 +1,29 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* Copyright (c) 2014-2022 OpenRCT2 developers
|
||||||
|
*
|
||||||
|
* For a complete list of all authors, please refer to contributors.md
|
||||||
|
* Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
|
||||||
|
*
|
||||||
|
* OpenRCT2 is licensed under the GNU General Public License version 3.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../../core/String.hpp"
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
#define TITLE_COMMAND_SCENARIO_LENGTH 64
|
||||||
|
|
||||||
|
namespace OpenRCT2::Title
|
||||||
|
{
|
||||||
|
struct LoadScenarioCommand
|
||||||
|
{
|
||||||
|
static constexpr const char* Name = "Load Scenario Command";
|
||||||
|
static constexpr const char* ScriptingName = "loadsc";
|
||||||
|
|
||||||
|
utf8 Scenario[TITLE_COMMAND_SCENARIO_LENGTH]{};
|
||||||
|
|
||||||
|
int16_t operator()(int16_t timer);
|
||||||
|
};
|
||||||
|
} // namespace OpenRCT2::Title
|
|
@ -0,0 +1,19 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* Copyright (c) 2014-2022 OpenRCT2 developers
|
||||||
|
*
|
||||||
|
* For a complete list of all authors, please refer to contributors.md
|
||||||
|
* Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
|
||||||
|
*
|
||||||
|
* OpenRCT2 is licensed under the GNU General Public License version 3.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#include "Restart.h"
|
||||||
|
|
||||||
|
namespace OpenRCT2::Title
|
||||||
|
{
|
||||||
|
int16_t RestartCommand::operator()(int16_t timer)
|
||||||
|
{
|
||||||
|
// The restart command is used as a tag, no logic required here.
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} // namespace OpenRCT2::Title
|
|
@ -0,0 +1,23 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* Copyright (c) 2014-2022 OpenRCT2 developers
|
||||||
|
*
|
||||||
|
* For a complete list of all authors, please refer to contributors.md
|
||||||
|
* Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
|
||||||
|
*
|
||||||
|
* OpenRCT2 is licensed under the GNU General Public License version 3.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace OpenRCT2::Title
|
||||||
|
{
|
||||||
|
struct RestartCommand
|
||||||
|
{
|
||||||
|
static constexpr const char* Name = "Restart Command";
|
||||||
|
static constexpr const char* ScriptingName = "restart";
|
||||||
|
|
||||||
|
int16_t operator()(int16_t timer);
|
||||||
|
};
|
||||||
|
} // namespace OpenRCT2::Title
|
|
@ -0,0 +1,29 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* Copyright (c) 2014-2022 OpenRCT2 developers
|
||||||
|
*
|
||||||
|
* For a complete list of all authors, please refer to contributors.md
|
||||||
|
* Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
|
||||||
|
*
|
||||||
|
* OpenRCT2 is licensed under the GNU General Public License version 3.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#include "RotateView.h"
|
||||||
|
|
||||||
|
#include "../../interface/Window.h"
|
||||||
|
|
||||||
|
namespace OpenRCT2::Title
|
||||||
|
{
|
||||||
|
int16_t RotateViewCommand::operator()(int16_t timer)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
} // namespace OpenRCT2::Title
|
|
@ -0,0 +1,25 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* Copyright (c) 2014-2022 OpenRCT2 developers
|
||||||
|
*
|
||||||
|
* For a complete list of all authors, please refer to contributors.md
|
||||||
|
* Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
|
||||||
|
*
|
||||||
|
* OpenRCT2 is licensed under the GNU General Public License version 3.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace OpenRCT2::Title
|
||||||
|
{
|
||||||
|
struct RotateViewCommand
|
||||||
|
{
|
||||||
|
static constexpr const char* Name = "Rotate View Command";
|
||||||
|
static constexpr const char* ScriptingName = "rotate";
|
||||||
|
|
||||||
|
uint8_t Rotations{};
|
||||||
|
|
||||||
|
int16_t operator()(int16_t timer);
|
||||||
|
};
|
||||||
|
} // namespace OpenRCT2::Title
|
|
@ -0,0 +1,38 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* Copyright (c) 2014-2022 OpenRCT2 developers
|
||||||
|
*
|
||||||
|
* For a complete list of all authors, please refer to contributors.md
|
||||||
|
* Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
|
||||||
|
*
|
||||||
|
* OpenRCT2 is licensed under the GNU General Public License version 3.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#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)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
} // namespace OpenRCT2::Title
|
|
@ -0,0 +1,30 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* Copyright (c) 2014-2022 OpenRCT2 developers
|
||||||
|
*
|
||||||
|
* For a complete list of all authors, please refer to contributors.md
|
||||||
|
* Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
|
||||||
|
*
|
||||||
|
* OpenRCT2 is licensed under the GNU General Public License version 3.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace OpenRCT2::Title
|
||||||
|
{
|
||||||
|
struct SetLocationCommand
|
||||||
|
{
|
||||||
|
static constexpr const char* Name = "Set Location Command";
|
||||||
|
static constexpr const char* ScriptingName = "location";
|
||||||
|
|
||||||
|
// TODO: Use TileCoordsXY instead
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
uint8_t X;
|
||||||
|
uint8_t Y;
|
||||||
|
} Location;
|
||||||
|
|
||||||
|
int16_t operator()(int16_t timer);
|
||||||
|
};
|
||||||
|
} // namespace OpenRCT2::Title
|
|
@ -0,0 +1,24 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* Copyright (c) 2014-2022 OpenRCT2 developers
|
||||||
|
*
|
||||||
|
* For a complete list of all authors, please refer to contributors.md
|
||||||
|
* Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
|
||||||
|
*
|
||||||
|
* OpenRCT2 is licensed under the GNU General Public License version 3.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#include "SetSpeed.h"
|
||||||
|
|
||||||
|
#include "../../Game.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
namespace OpenRCT2::Title
|
||||||
|
{
|
||||||
|
int16_t SetSpeedCommand::operator()(int16_t timer)
|
||||||
|
{
|
||||||
|
gGameSpeed = std::clamp<uint8_t>(Speed, 1, 4);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} // namespace OpenRCT2::Title
|
|
@ -0,0 +1,25 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* Copyright (c) 2014-2022 OpenRCT2 developers
|
||||||
|
*
|
||||||
|
* For a complete list of all authors, please refer to contributors.md
|
||||||
|
* Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
|
||||||
|
*
|
||||||
|
* OpenRCT2 is licensed under the GNU General Public License version 3.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace OpenRCT2::Title
|
||||||
|
{
|
||||||
|
struct SetSpeedCommand
|
||||||
|
{
|
||||||
|
static constexpr const char* Name = "Set Speed Command";
|
||||||
|
static constexpr const char* ScriptingName = "speed";
|
||||||
|
|
||||||
|
uint8_t Speed{};
|
||||||
|
|
||||||
|
int16_t operator()(int16_t timer);
|
||||||
|
};
|
||||||
|
} // namespace OpenRCT2::Title
|
|
@ -0,0 +1,27 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* Copyright (c) 2014-2022 OpenRCT2 developers
|
||||||
|
*
|
||||||
|
* For a complete list of all authors, please refer to contributors.md
|
||||||
|
* Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
|
||||||
|
*
|
||||||
|
* OpenRCT2 is licensed under the GNU General Public License version 3.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#include "SetZoom.h"
|
||||||
|
|
||||||
|
#include "../../interface/Window.h"
|
||||||
|
#include "../../interface/ZoomLevel.h"
|
||||||
|
|
||||||
|
namespace OpenRCT2::Title
|
||||||
|
{
|
||||||
|
int16_t SetZoomCommand::operator()(int16_t timer)
|
||||||
|
{
|
||||||
|
rct_window* w = window_get_main();
|
||||||
|
if (w != nullptr)
|
||||||
|
{
|
||||||
|
window_zoom_set(w, ZoomLevel{ static_cast<int8_t>(Zoom) }, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} // namespace OpenRCT2::Title
|
|
@ -0,0 +1,26 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* Copyright (c) 2014-2022 OpenRCT2 developers
|
||||||
|
*
|
||||||
|
* For a complete list of all authors, please refer to contributors.md
|
||||||
|
* Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
|
||||||
|
*
|
||||||
|
* OpenRCT2 is licensed under the GNU General Public License version 3.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace OpenRCT2::Title
|
||||||
|
{
|
||||||
|
struct SetZoomCommand
|
||||||
|
{
|
||||||
|
static constexpr const char* Name = "Set Zoom Command";
|
||||||
|
static constexpr const char* ScriptingName = "zoom";
|
||||||
|
|
||||||
|
// TODO: Use ZoomLevel instead
|
||||||
|
uint8_t Zoom{};
|
||||||
|
|
||||||
|
int16_t operator()(int16_t timer);
|
||||||
|
};
|
||||||
|
} // namespace OpenRCT2::Title
|
|
@ -0,0 +1,23 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* Copyright (c) 2014-2022 OpenRCT2 developers
|
||||||
|
*
|
||||||
|
* For a complete list of all authors, please refer to contributors.md
|
||||||
|
* Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
|
||||||
|
*
|
||||||
|
* OpenRCT2 is licensed under the GNU General Public License version 3.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#include "Wait.h"
|
||||||
|
|
||||||
|
#include "../../Context.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
namespace OpenRCT2::Title
|
||||||
|
{
|
||||||
|
int16_t WaitCommand::operator()(int16_t timer)
|
||||||
|
{
|
||||||
|
// Return number of game ticks this wait command lasts
|
||||||
|
return std::max<int16_t>(1, GAME_UPDATE_FPS * Milliseconds / 1000);
|
||||||
|
}
|
||||||
|
} // namespace OpenRCT2::Title
|
|
@ -0,0 +1,25 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* Copyright (c) 2014-2022 OpenRCT2 developers
|
||||||
|
*
|
||||||
|
* For a complete list of all authors, please refer to contributors.md
|
||||||
|
* Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2
|
||||||
|
*
|
||||||
|
* OpenRCT2 is licensed under the GNU General Public License version 3.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace OpenRCT2::Title
|
||||||
|
{
|
||||||
|
struct WaitCommand
|
||||||
|
{
|
||||||
|
static constexpr const char* Name = "Wait Command";
|
||||||
|
static constexpr const char* ScriptingName = "wait";
|
||||||
|
|
||||||
|
uint16_t Milliseconds{};
|
||||||
|
|
||||||
|
int16_t operator()(int16_t timer);
|
||||||
|
};
|
||||||
|
} // namespace OpenRCT2::Title
|
File diff suppressed because it is too large
Load Diff
|
@ -10,81 +10,56 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "../common.h"
|
#include "../common.h"
|
||||||
#include "../localisation/Localisation.h"
|
|
||||||
#include "../openrct2/core/IStream.hpp"
|
#include "../openrct2/core/IStream.hpp"
|
||||||
|
#include "Command/End.h"
|
||||||
|
#include "Command/FollowEntity.h"
|
||||||
|
#include "Command/LoadPark.h"
|
||||||
|
#include "Command/LoadScenario.h"
|
||||||
|
#include "Command/Restart.h"
|
||||||
|
#include "Command/RotateView.h"
|
||||||
|
#include "Command/SetLocation.h"
|
||||||
|
#include "Command/SetSpeed.h"
|
||||||
|
#include "Command/SetZoom.h"
|
||||||
|
#include "Command/Wait.h"
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <variant>
|
||||||
|
|
||||||
#define TITLE_COMMAND_SCENARIO_LENGTH 64
|
namespace OpenRCT2::Title
|
||||||
enum class TitleScript : uint8_t;
|
|
||||||
struct TitleCommand
|
|
||||||
{
|
{
|
||||||
TitleScript Type;
|
using TitleCommand = std::variant<
|
||||||
union
|
WaitCommand, SetLocationCommand, RotateViewCommand, SetZoomCommand, FollowEntityCommand, RestartCommand,
|
||||||
|
LoadParkCommand, EndCommand, SetSpeedCommand, LoadScenarioCommand>;
|
||||||
|
|
||||||
|
struct TitleSequence
|
||||||
{
|
{
|
||||||
uint8_t SaveIndex; // LOAD (this index is internal only)
|
std::string Name;
|
||||||
struct // LOCATION
|
std::string Path;
|
||||||
{
|
|
||||||
uint8_t X;
|
std::vector<TitleCommand> Commands;
|
||||||
uint8_t Y;
|
std::vector<std::string> Saves;
|
||||||
} Location;
|
|
||||||
uint8_t Rotations; // ROTATE (counter-clockwise)
|
bool IsZip = false;
|
||||||
uint8_t Zoom; // ZOOM
|
|
||||||
struct // FOLLOW
|
|
||||||
{
|
|
||||||
EntityId SpriteIndex;
|
|
||||||
utf8 SpriteName[USER_STRING_MAX_LENGTH];
|
|
||||||
} Follow;
|
|
||||||
uint8_t Speed; // SPEED
|
|
||||||
uint16_t Milliseconds; // WAIT
|
|
||||||
utf8 Scenario[TITLE_COMMAND_SCENARIO_LENGTH]; // LOADSC
|
|
||||||
};
|
};
|
||||||
};
|
|
||||||
|
|
||||||
struct TitleSequence
|
struct TitleSequenceParkHandle
|
||||||
{
|
{
|
||||||
std::string Name;
|
std::string HintPath;
|
||||||
std::string Path;
|
std::unique_ptr<OpenRCT2::IStream> Stream;
|
||||||
|
};
|
||||||
|
|
||||||
std::vector<TitleCommand> Commands;
|
constexpr const utf8* TITLE_SEQUENCE_EXTENSION = ".parkseq";
|
||||||
std::vector<std::string> Saves;
|
constexpr uint8_t SAVE_INDEX_INVALID = UINT8_MAX;
|
||||||
|
|
||||||
bool IsZip = false;
|
[[nodiscard]] std::unique_ptr<TitleSequence> CreateTitleSequence();
|
||||||
};
|
[[nodiscard]] std::unique_ptr<TitleSequence> LoadTitleSequence(const std::string& path);
|
||||||
|
[[nodiscard]] std::unique_ptr<TitleSequenceParkHandle> TitleSequenceGetParkHandle(const TitleSequence& seq, size_t index);
|
||||||
|
|
||||||
struct TitleSequenceParkHandle
|
bool TitleSequenceSave(const TitleSequence& seq);
|
||||||
{
|
bool TitleSequenceAddPark(TitleSequence& seq, const utf8* path, const utf8* name);
|
||||||
std::string HintPath;
|
bool TitleSequenceRenamePark(TitleSequence& seq, size_t index, const utf8* name);
|
||||||
std::unique_ptr<OpenRCT2::IStream> Stream;
|
bool TitleSequenceRemovePark(TitleSequence& seq, size_t index);
|
||||||
};
|
|
||||||
|
|
||||||
enum class TitleScript : uint8_t
|
bool TitleSequenceIsLoadCommand(const TitleCommand& command);
|
||||||
{
|
} // namespace OpenRCT2::Title
|
||||||
Undefined = 0xFF,
|
|
||||||
Wait = 0,
|
|
||||||
Location,
|
|
||||||
Rotate,
|
|
||||||
Zoom,
|
|
||||||
Follow,
|
|
||||||
Restart,
|
|
||||||
Load,
|
|
||||||
End,
|
|
||||||
Speed,
|
|
||||||
Loop,
|
|
||||||
EndLoop,
|
|
||||||
LoadSc,
|
|
||||||
};
|
|
||||||
|
|
||||||
constexpr const utf8* TITLE_SEQUENCE_EXTENSION = ".parkseq";
|
|
||||||
constexpr uint8_t SAVE_INDEX_INVALID = UINT8_MAX;
|
|
||||||
|
|
||||||
[[nodiscard]] std::unique_ptr<TitleSequence> CreateTitleSequence();
|
|
||||||
[[nodiscard]] std::unique_ptr<TitleSequence> LoadTitleSequence(const std::string& path);
|
|
||||||
[[nodiscard]] std::unique_ptr<TitleSequenceParkHandle> TitleSequenceGetParkHandle(const TitleSequence& seq, size_t index);
|
|
||||||
|
|
||||||
bool TitleSequenceSave(const TitleSequence& seq);
|
|
||||||
bool TitleSequenceAddPark(TitleSequence& seq, const utf8* path, const utf8* name);
|
|
||||||
bool TitleSequenceRenamePark(TitleSequence& seq, size_t index, const utf8* name);
|
|
||||||
bool TitleSequenceRemovePark(TitleSequence& seq, size_t index);
|
|
||||||
|
|
||||||
bool TitleSequenceIsLoadCommand(const TitleCommand& command);
|
|
||||||
|
|
|
@ -103,7 +103,7 @@ namespace TitleSequenceManager
|
||||||
auto newPath = Path::Combine(Path::GetDirectory(oldPath), newName);
|
auto newPath = Path::Combine(Path::GetDirectory(oldPath), newName);
|
||||||
if (item->IsZip)
|
if (item->IsZip)
|
||||||
{
|
{
|
||||||
newPath += TITLE_SEQUENCE_EXTENSION;
|
newPath += OpenRCT2::Title::TITLE_SEQUENCE_EXTENSION;
|
||||||
File::Move(oldPath, newPath);
|
File::Move(oldPath, newPath);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -138,7 +138,7 @@ namespace TitleSequenceManager
|
||||||
|
|
||||||
size_t CreateItem(const utf8* name)
|
size_t CreateItem(const utf8* name)
|
||||||
{
|
{
|
||||||
auto seq = CreateTitleSequence();
|
auto seq = OpenRCT2::Title::CreateTitleSequence();
|
||||||
seq->Name = name;
|
seq->Name = name;
|
||||||
seq->Path = GetNewTitleSequencePath(seq->Name, true);
|
seq->Path = GetNewTitleSequencePath(seq->Name, true);
|
||||||
seq->IsZip = true;
|
seq->IsZip = true;
|
||||||
|
@ -159,7 +159,7 @@ namespace TitleSequenceManager
|
||||||
auto path = Path::Combine(GetUserSequencesPath(), name);
|
auto path = Path::Combine(GetUserSequencesPath(), name);
|
||||||
if (isZip)
|
if (isZip)
|
||||||
{
|
{
|
||||||
path += TITLE_SEQUENCE_EXTENSION;
|
path += OpenRCT2::Title::TITLE_SEQUENCE_EXTENSION;
|
||||||
}
|
}
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue