1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2026-01-15 11:03:00 +01:00

Make title sequence commands list variadic

This commit is contained in:
Hielke Morsink
2022-06-17 23:34:37 +02:00
parent 854655af55
commit debdb0bcda
2 changed files with 165 additions and 138 deletions

View File

@@ -28,7 +28,11 @@
#include <algorithm>
#include <array>
#include <optional>
#include <memory>
#include <type_traits>
#include <string>
#include <utility>
#include <vector>
static std::vector<std::string> GetSaves(const std::string& path);
@@ -270,19 +274,23 @@ bool TitleSequenceRemovePark(TitleSequence& seq, size_t index)
// Update load commands
for (auto& command : seq.Commands)
{
if (command.Type == TitleScript::Load)
{
if (command.SaveIndex == index)
{
// Park no longer exists, so reset load command to invalid
command.SaveIndex = SAVE_INDEX_INVALID;
}
else if (command.SaveIndex > index)
{
// Park index will have shifted by -1
command.SaveIndex--;
}
}
std::visit(
[index](auto&& command) {
if constexpr (std::is_same_v<std::decay<decltype(command)>, LoadParkCommand>)
{
if (command.SaveIndex == index)
{
// Park no longer exists, so reset load command to invalid
command.SaveIndex = SAVE_INDEX_INVALID;
}
else if (command.SaveIndex > index)
{
// Park index will have shifted by -1
command.SaveIndex--;
}
}
},
command);
}
return true;
@@ -328,73 +336,75 @@ static std::vector<TitleCommand> LegacyScriptRead(const std::vector<uint8_t>& sc
LegacyScriptGetLine(&fs, parts);
const char* token = parts[0].data();
TitleCommand command = {};
command.Type = TitleScript::Undefined;
std::optional<TitleCommand> command = std::nullopt;
if (token[0] != 0)
{
if (_stricmp(token, "LOAD") == 0)
{
command.Type = TitleScript::Load;
command.SaveIndex = SAVE_INDEX_INVALID;
auto saveIndex = SAVE_INDEX_INVALID;
for (size_t i = 0; i < saves.size(); i++)
{
if (String::Equals(parts[1].data(), saves[i], true))
{
command.SaveIndex = static_cast<uint8_t>(i);
saveIndex = static_cast<uint8_t>(i);
break;
}
}
command = LoadParkCommand{ saveIndex };
}
else if (_stricmp(token, "LOCATION") == 0)
{
command.Type = TitleScript::Location;
command.Location.X = atoi(parts[1].data()) & 0xFF;
command.Location.Y = atoi(parts[2].data()) & 0xFF;
uint8_t locationX = atoi(parts[1].data()) & 0xFF;
uint8_t locationY = atoi(parts[2].data()) & 0xFF;
command = SetLocationCommand{ locationX, locationY };
}
else if (_stricmp(token, "ROTATE") == 0)
{
command.Type = TitleScript::Rotate;
command.Rotations = atoi(parts[1].data()) & 0xFF;
uint8_t rotations = atoi(parts[1].data()) & 0xFF;
command = RotateViewCommand{ rotations };
}
else if (_stricmp(token, "ZOOM") == 0)
{
command.Type = TitleScript::Zoom;
command.Zoom = atoi(parts[1].data()) & 0xFF;
uint8_t zoom = atoi(parts[1].data()) & 0xFF;
command = SetZoomCommand{ zoom };
}
else if (_stricmp(token, "SPEED") == 0)
{
command.Type = TitleScript::Speed;
command.Speed = std::max(1, std::min(4, atoi(parts[1].data()) & 0xFF));
uint8_t speed = std::max(1, std::min(4, atoi(parts[1].data()) & 0xFF));
command = SetSpeedCommand{ speed };
}
else if (_stricmp(token, "FOLLOW") == 0)
{
command.Type = TitleScript::Follow;
command.Follow.SpriteIndex = EntityId::FromUnderlying(atoi(parts[1].data()) & 0xFFFF);
safe_strcpy(command.Follow.SpriteName, parts[2].data(), USER_STRING_MAX_LENGTH);
auto entityID = EntityId::FromUnderlying(atoi(parts[1].data()) & 0xFFFF);
auto followCommand = FollowEntityCommand{ entityID };
safe_strcpy(followCommand.Follow.SpriteName, parts[2].data(), USER_STRING_MAX_LENGTH);
command = followCommand;
}
else if (_stricmp(token, "WAIT") == 0)
{
command.Type = TitleScript::Wait;
command.Milliseconds = atoi(parts[1].data()) & 0xFFFF;
uint16_t milliseconds = atoi(parts[1].data()) & 0xFFFF;
command = WaitCommand{ milliseconds };
}
else if (_stricmp(token, "RESTART") == 0)
{
command.Type = TitleScript::Restart;
command = RestartCommand{};
}
else if (_stricmp(token, "END") == 0)
{
command.Type = TitleScript::End;
command = EndCommand{};
}
else if (_stricmp(token, "LOADSC") == 0)
{
command.Type = TitleScript::LoadSc;
safe_strcpy(command.Scenario, parts[1].data(), sizeof(command.Scenario));
auto loadScenarioCommand = LoadScenarioCommand{};
safe_strcpy(loadScenarioCommand.Scenario, parts[1].data(), sizeof(loadScenarioCommand.Scenario));
command = loadScenarioCommand;
}
}
if (command.Type != TitleScript::Undefined)
if (command.has_value())
{
commands.push_back(std::move(command));
commands.push_back(std::move(*command));
}
} while (fs.GetPosition() < fs.GetLength());
return commands;
@@ -495,67 +505,74 @@ static std::string LegacyScriptWrite(const TitleSequence& seq)
sb.Append("\n");
for (const auto& command : seq.Commands)
{
switch (command.Type)
{
case TitleScript::Load:
if (command.SaveIndex < seq.Saves.size())
std::visit(
[&buffer, &seq, &sb](auto&& command) {
using T = std::decay<decltype(command)>::type;
if constexpr (std::is_same_v<T, LoadParkCommand>)
{
sb.Append("LOAD ");
sb.Append(seq.Saves[command.SaveIndex].c_str());
if (command.SaveIndex < seq.Saves.size())
{
sb.Append("LOAD ");
sb.Append(seq.Saves[command.SaveIndex].c_str());
}
else
{
sb.Append("LOAD <No save file>");
}
}
else
else if constexpr (std::is_same_v<T, LoadScenarioCommand>)
{
sb.Append("LOAD <No save file>");
if (command.Scenario[0] == '\0')
{
sb.Append("LOADSC <No scenario name>");
}
else
{
sb.Append("LOADSC ");
sb.Append(command.Scenario);
}
}
break;
case TitleScript::LoadSc:
if (command.Scenario[0] == '\0')
else if constexpr (std::is_same_v<T, SetLocationCommand>)
{
sb.Append("LOADSC <No scenario name>");
String::Format(buffer, sizeof(buffer), "LOCATION %u %u", command.Location.X, command.Location.Y);
sb.Append(buffer);
}
else
else if constexpr (std::is_same_v<T, RotateViewCommand>)
{
sb.Append("LOADSC ");
sb.Append(command.Scenario);
String::Format(buffer, sizeof(buffer), "ROTATE %u", command.Rotations);
sb.Append(buffer);
}
break;
case TitleScript::Undefined:
break;
case TitleScript::Loop:
break;
case TitleScript::EndLoop:
break;
case TitleScript::Location:
String::Format(buffer, sizeof(buffer), "LOCATION %u %u", command.Location.X, command.Location.Y);
sb.Append(buffer);
break;
case TitleScript::Rotate:
String::Format(buffer, sizeof(buffer), "ROTATE %u", command.Rotations);
sb.Append(buffer);
break;
case TitleScript::Zoom:
String::Format(buffer, sizeof(buffer), "ZOOM %u", command.Zoom);
sb.Append(buffer);
break;
case TitleScript::Follow:
String::Format(buffer, sizeof(buffer), "FOLLOW %u ", command.Follow.SpriteIndex);
sb.Append(buffer);
sb.Append(command.Follow.SpriteName);
break;
case TitleScript::Speed:
String::Format(buffer, sizeof(buffer), "SPEED %u", command.Speed);
sb.Append(buffer);
break;
case TitleScript::Wait:
String::Format(buffer, sizeof(buffer), "WAIT %u", command.Milliseconds);
sb.Append(buffer);
break;
case TitleScript::Restart:
sb.Append("RESTART");
break;
case TitleScript::End:
sb.Append("END");
}
else if constexpr (std::is_same_v<T, SetZoomCommand>)
{
String::Format(buffer, sizeof(buffer), "ZOOM %u", command.Zoom);
sb.Append(buffer);
}
else if constexpr (std::is_same_v<T, FollowEntityCommand>)
{
String::Format(buffer, sizeof(buffer), "FOLLOW %u ", command.Follow.SpriteIndex);
sb.Append(buffer);
sb.Append(command.Follow.SpriteName);
}
else if constexpr (std::is_same_v<T, SetSpeedCommand>)
{
String::Format(buffer, sizeof(buffer), "SPEED %u", command.Speed);
sb.Append(buffer);
}
else if constexpr (std::is_same_v<T, WaitCommand>)
{
String::Format(buffer, sizeof(buffer), "WAIT %u", command.Milliseconds);
sb.Append(buffer);
}
else if constexpr (std::is_same_v<T, RestartCommand>)
{
sb.Append("RESTART");
}
else if constexpr (std::is_same_v<T, EndCommand>)
{
sb.Append("END");
}
},
command);
sb.Append("\n");
}
@@ -564,12 +581,5 @@ static std::string LegacyScriptWrite(const TitleSequence& seq)
bool TitleSequenceIsLoadCommand(const TitleCommand& command)
{
switch (command.Type)
{
case TitleScript::Load:
case TitleScript::LoadSc:
return true;
default:
return false;
}
return std::holds_alternative<LoadParkCommand>(command) || std::holds_alternative<LoadScenarioCommand>(command);
}

View File

@@ -14,32 +14,66 @@
#include "../openrct2/core/IStream.hpp"
#include <memory>
#include <variant>
#define TITLE_COMMAND_SCENARIO_LENGTH 64
enum class TitleScript : uint8_t;
struct TitleCommand
struct WaitCommand
{
TitleScript Type;
union
{
uint8_t SaveIndex; // LOAD (this index is internal only)
struct // LOCATION
{
uint8_t X;
uint8_t Y;
} Location;
uint8_t Rotations; // ROTATE (counter-clockwise)
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
};
uint16_t Milliseconds;
};
struct SetLocationCommand
{
struct
{
uint8_t X;
uint8_t Y;
} Location;
};
struct RotateViewCommand
{
uint8_t Rotations;
};
struct SetZoomCommand
{
uint8_t Zoom;
};
struct FollowEntityCommand
{
struct
{
EntityId SpriteIndex;
utf8 SpriteName[USER_STRING_MAX_LENGTH];
} Follow;
};
struct RestartCommand
{
};
struct LoadParkCommand
{
uint8_t SaveIndex;
};
struct EndCommand
{
};
struct SetSpeedCommand
{
uint8_t Speed;
};
struct LoopCommand
{
};
struct EndLoopCommand
{
};
struct LoadScenarioCommand
{
utf8 Scenario[TITLE_COMMAND_SCENARIO_LENGTH];
};
using TitleCommand = std::variant<
WaitCommand, SetLocationCommand, RotateViewCommand, SetZoomCommand, FollowEntityCommand, RestartCommand, LoadParkCommand,
EndCommand, SetSpeedCommand, LoopCommand, EndLoopCommand, LoadScenarioCommand>;
struct TitleSequence
{
@@ -58,23 +92,6 @@ struct TitleSequenceParkHandle
std::unique_ptr<OpenRCT2::IStream> Stream;
};
enum class TitleScript : uint8_t
{
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;