diff --git a/src/openrct2/interface/InteractiveConsole.cpp b/src/openrct2/interface/InteractiveConsole.cpp
index eed0710626..67b5ed1930 100644
--- a/src/openrct2/interface/InteractiveConsole.cpp
+++ b/src/openrct2/interface/InteractiveConsole.cpp
@@ -1299,7 +1299,7 @@ constexpr std::array _objectTypeNames = {
"Scenery groups",
"Park entrances",
"Water",
- "ScenarioText",
+ "Scenario Text",
"Terrain Surface",
"Terrain Edges",
"Stations",
diff --git a/src/openrct2/libopenrct2.vcxproj b/src/openrct2/libopenrct2.vcxproj
index f64c17b5a6..b88e708d96 100644
--- a/src/openrct2/libopenrct2.vcxproj
+++ b/src/openrct2/libopenrct2.vcxproj
@@ -355,6 +355,7 @@
+
@@ -880,6 +881,7 @@
+
diff --git a/src/openrct2/object/ObjectFactory.cpp b/src/openrct2/object/ObjectFactory.cpp
index d4b47fab8a..31a3f58cba 100644
--- a/src/openrct2/object/ObjectFactory.cpp
+++ b/src/openrct2/object/ObjectFactory.cpp
@@ -38,6 +38,7 @@
#include "PathAdditionObject.h"
#include "PeepNamesObject.h"
#include "RideObject.h"
+#include "ScenarioTextObject.h"
#include "SceneryGroupObject.h"
#include "SmallSceneryObject.h"
#include "StationObject.h"
@@ -363,6 +364,7 @@ namespace OpenRCT2::ObjectFactory
result = std::make_unique();
break;
case ObjectType::ScenarioText:
+ result = std::make_unique();
break;
case ObjectType::TerrainSurface:
result = std::make_unique();
@@ -414,6 +416,8 @@ namespace OpenRCT2::ObjectFactory
return ObjectType::ParkEntrance;
if (s == "water")
return ObjectType::Water;
+ if (s == "scenario_text")
+ return ObjectType::ScenarioText;
if (s == "terrain_surface")
return ObjectType::TerrainSurface;
if (s == "terrain_edge")
diff --git a/src/openrct2/object/ObjectLimits.h b/src/openrct2/object/ObjectLimits.h
index d8b9f599e7..5af71860ec 100644
--- a/src/openrct2/object/ObjectLimits.h
+++ b/src/openrct2/object/ObjectLimits.h
@@ -23,7 +23,7 @@ constexpr uint16_t kMaxPathAdditionObjects = 255;
constexpr uint16_t kMaxSceneryGroupObjects = 255;
constexpr uint16_t kMaxParkEntranceObjects = 4;
constexpr uint16_t kMaxWaterObjects = 1;
-constexpr uint16_t kMaxScenarioTextObjects = 0;
+constexpr uint16_t kMaxScenarioTextObjects = 1;
constexpr uint16_t kMaxTerrainSurfaceObjects = 255;
constexpr uint16_t kMaxTerrainEdgeObjects = 255;
constexpr uint16_t kMaxStationObjects = 255;
diff --git a/src/openrct2/object/ScenarioTextObject.cpp b/src/openrct2/object/ScenarioTextObject.cpp
new file mode 100644
index 0000000000..b82e46070d
--- /dev/null
+++ b/src/openrct2/object/ScenarioTextObject.cpp
@@ -0,0 +1,46 @@
+/*****************************************************************************
+ * Copyright (c) 2014-2024 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 "ScenarioTextObject.h"
+
+#include "../Context.h"
+#include "../PlatformEnvironment.h"
+#include "../core/Guard.hpp"
+#include "../core/Json.hpp"
+
+using namespace OpenRCT2;
+
+void ScenarioTextObject::Load()
+{
+}
+
+void ScenarioTextObject::Unload()
+{
+}
+
+void ScenarioTextObject::ReadJson(IReadObjectContext* context, json_t& root)
+{
+ Guard::Assert(root.is_object(), "ScenarioTextObject::ReadJson expects parameter root to be an object");
+ PopulateTablesFromJson(context, root);
+}
+
+std::string ScenarioTextObject::GetScenarioName()
+{
+ return GetStringTable().GetString(ObjectStringID::SCENARIO_NAME);
+}
+
+std::string ScenarioTextObject::GetParkName()
+{
+ return GetStringTable().GetString(ObjectStringID::PARK_NAME);
+}
+
+std::string ScenarioTextObject::GetScenarioDetails()
+{
+ return GetStringTable().GetString(ObjectStringID::SCENARIO_DETAILS);
+}
diff --git a/src/openrct2/object/ScenarioTextObject.h b/src/openrct2/object/ScenarioTextObject.h
new file mode 100644
index 0000000000..5173ede439
--- /dev/null
+++ b/src/openrct2/object/ScenarioTextObject.h
@@ -0,0 +1,29 @@
+/*****************************************************************************
+ * Copyright (c) 2014-2024 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/IStream.hpp"
+#include "Object.h"
+
+#include
+
+class ScenarioTextObject final : public Object
+{
+public:
+ static constexpr ObjectType kObjectType = ObjectType::ScenarioText;
+
+ void ReadJson(IReadObjectContext* context, json_t& root) override;
+ void Load() override;
+ void Unload() override;
+
+ std::string GetScenarioName();
+ std::string GetParkName();
+ std::string GetScenarioDetails();
+};
diff --git a/src/openrct2/scenario/Scenario.cpp b/src/openrct2/scenario/Scenario.cpp
index 99e4a862c0..d07bcdbc49 100644
--- a/src/openrct2/scenario/Scenario.cpp
+++ b/src/openrct2/scenario/Scenario.cpp
@@ -41,6 +41,7 @@
#include "../object/ObjectEntryManager.h"
#include "../object/ObjectList.h"
#include "../object/ObjectManager.h"
+#include "../object/ScenarioTextObject.h"
#include "../object/WaterEntry.h"
#include "../platform/Platform.h"
#include "../profiling/Profiling.h"
@@ -107,25 +108,14 @@ void ScenarioReset(GameState_t& gameState)
gameState.HistoricalProfit = gameState.InitialCash - gameState.BankLoan;
gameState.Cash = gameState.InitialCash;
+ auto& objManager = GetContext()->GetObjectManager();
+ if (auto* object = objManager.GetLoadedObject(ObjectType::ScenarioText, 0))
{
- auto normalisedName = ScenarioSources::NormaliseName(gameState.ScenarioName);
+ auto* textObject = reinterpret_cast(object);
- StringId localisedStringIds[3];
- if (LanguageGetLocalisedScenarioStrings(normalisedName, localisedStringIds))
- {
- if (localisedStringIds[0] != STR_NONE)
- {
- gameState.ScenarioName = LanguageGetString(localisedStringIds[0]);
- }
- if (localisedStringIds[1] != STR_NONE)
- {
- gameState.Park.Name = LanguageGetString(localisedStringIds[1]);
- }
- if (localisedStringIds[2] != STR_NONE)
- {
- gameState.ScenarioDetails = LanguageGetString(localisedStringIds[2]);
- }
- }
+ gameState.ScenarioName = textObject->GetScenarioName();
+ gameState.Park.Name = textObject->GetParkName();
+ gameState.ScenarioDetails = textObject->GetScenarioDetails();
}
// Set the last saved game path
@@ -154,7 +144,6 @@ void ScenarioReset(GameState_t& gameState)
MapCountRemainingLandRights();
Staff::ResetStats();
- auto& objManager = GetContext()->GetObjectManager();
gameState.LastEntranceStyle = objManager.GetLoadedObjectEntryIndex("rct2.station.plain");
if (gameState.LastEntranceStyle == OBJECT_ENTRY_INDEX_NULL)
{