diff --git a/openrct2.vcxproj b/openrct2.vcxproj
index 34dfd4296f..78e43f5706 100644
--- a/openrct2.vcxproj
+++ b/openrct2.vcxproj
@@ -123,6 +123,7 @@
+
@@ -429,6 +430,7 @@
+
diff --git a/src/drawing/drawing.h b/src/drawing/drawing.h
index 04367bc40e..4c0d568ea8 100644
--- a/src/drawing/drawing.h
+++ b/src/drawing/drawing.h
@@ -176,6 +176,8 @@ int gfx_load_g2();
void gfx_unload_g1();
void gfx_unload_g2();
rct_g1_element* gfx_get_g1_element(int image_id);
+uint32 gfx_object_allocate_images(const rct_g1_element * images, uint32 count);
+void gfx_object_free_images(uint32 baseImageId, uint32 count);
void sub_68371D();
void FASTCALL gfx_rle_sprite_to_buffer(const uint8* RESTRICT source_bits_pointer, uint8* RESTRICT dest_bits_pointer, const uint8* RESTRICT palette_pointer, const rct_drawpixelinfo * RESTRICT dpi, int image_type, int source_y_start, int height, int source_x_start, int width);
void FASTCALL gfx_draw_sprite(rct_drawpixelinfo *dpi, int image_id, int x, int y, uint32 tertiary_colour);
diff --git a/src/drawing/sprite.c b/src/drawing/sprite.c
index 26458bb1ab..0c16ef28cc 100644
--- a/src/drawing/sprite.c
+++ b/src/drawing/sprite.c
@@ -173,6 +173,29 @@ int gfx_load_g2()
return 0;
}
+static uint32 _nextImageId = 29294;
+
+uint32 gfx_object_allocate_images(const rct_g1_element * images, uint32 count)
+{
+ uint32 baseImageId = _nextImageId;
+ for (uint32 i = 0; i < count; i++) {
+ uint32 imageId = _nextImageId;
+ if (imageId >= 291438) {
+ log_error("Reached maximum image limit.");
+ break;
+ }
+
+ g1Elements[imageId] = images[i];
+ drawing_engine_invalidate_image(imageId);
+ _nextImageId++;
+ }
+ return baseImageId;
+}
+
+void gfx_object_free_images(uint32 baseImageId, uint32 count)
+{
+}
+
/**
* This function looks like it initialises the 0x009E3CE4 array which references sprites used for background / palette mixing or
* something. Further investigation is needed.
diff --git a/src/localisation/language.cpp b/src/localisation/language.cpp
index 43c9e635f0..70f357c162 100644
--- a/src/localisation/language.cpp
+++ b/src/localisation/language.cpp
@@ -455,4 +455,17 @@ bool language_get_localised_scenario_strings(const utf8 *scenarioFilename, rct_s
outStringIds[2] != STR_NONE;
}
+static rct_string_id _nextObjectStringId = NONSTEX_BASE_STRING_ID;
+
+rct_string_id language_allocate_object_string(const utf8 * target)
+{
+ rct_string_id stringId = _nextObjectStringId++;
+ _languageCurrent->SetString(stringId, target);
+ return stringId;
+}
+
+void language_free_object_string(rct_string_id stringId)
+{
+}
+
}
diff --git a/src/localisation/language.h b/src/localisation/language.h
index 8e2d1f8511..4bcab7a61f 100644
--- a/src/localisation/language.h
+++ b/src/localisation/language.h
@@ -82,5 +82,7 @@ wchar_t *utf8_to_widechar(const utf8 *src);
utf8 *widechar_to_utf8(const wchar_t *src);
bool language_get_localised_scenario_strings(const utf8 *scenarioFilename, rct_string_id *outStringIds);
+rct_string_id language_allocate_object_string(const utf8 * target);
+void language_free_object_string(rct_string_id stringId);
#endif
diff --git a/src/object.c b/src/object.c
index ce0d7c86e3..225cf5518f 100644
--- a/src/object.c
+++ b/src/object.c
@@ -149,7 +149,7 @@ int object_load_file(int groupIndex, const rct_object_entry *entry, int* chunkSi
*
* rct2: 0x006A985D
*/
-int object_load_chunk(int groupIndex, rct_object_entry *entry, int* chunkSize)
+int object_load_chunk_old(int groupIndex, rct_object_entry *entry, int* chunkSize)
{
// Alow chunkSize to be null
int tempChunkSize;
diff --git a/src/object/EntranceObject.cpp b/src/object/EntranceObject.cpp
index d1b0e3a45b..edd1db42b5 100644
--- a/src/object/EntranceObject.cpp
+++ b/src/object/EntranceObject.cpp
@@ -17,6 +17,12 @@
#include "../core/IStream.hpp"
#include "EntranceObject.h"
+extern "C"
+{
+ #include "../drawing/drawing.h"
+ #include "../localisation/localisation.h"
+}
+
enum OBJ_STRING_ID
{
OBJ_STRING_ID_NAME,
@@ -35,12 +41,13 @@ void EntranceObject::ReadLegacy(IStream * stream)
void EntranceObject::Load()
{
-
+ _legacyType.string_idx = language_allocate_object_string(GetName());
+ _legacyType.image_id = gfx_object_allocate_images(ImageTable.GetImages(), ImageTable.GetCount());
}
void EntranceObject::Unload()
{
-
+ language_free_object_string(_legacyType.string_idx);
}
const utf8 * EntranceObject::GetName()
diff --git a/src/object/ImageTable.h b/src/object/ImageTable.h
index 5514694fb4..788501cf44 100644
--- a/src/object/ImageTable.h
+++ b/src/object/ImageTable.h
@@ -36,5 +36,7 @@ private:
public:
~ImageTable();
- void Read(IStream * stream);
+ void Read(IStream * stream);
+ const rct_g1_element * GetImages() const { return _entries.data(); }
+ uint32 GetCount() const { return _entries.size(); };
};
\ No newline at end of file
diff --git a/src/object/Object.h b/src/object/Object.h
index a68b19c03c..adeebc0894 100644
--- a/src/object/Object.h
+++ b/src/object/Object.h
@@ -48,5 +48,6 @@ public:
virtual void Load() abstract;
virtual void Unload() abstract;
- virtual const utf8 * GetName() abstract;
+ virtual uint8 GetObjectType() { return _objectEntry.flags & 0x0F; }
+ virtual const utf8 * GetName() abstract;
};
diff --git a/src/object/ObjectFactory.cpp b/src/object/ObjectFactory.cpp
index 957f10e34b..7cd94070fa 100644
--- a/src/object/ObjectFactory.cpp
+++ b/src/object/ObjectFactory.cpp
@@ -20,6 +20,7 @@
#include "EntranceObject.h"
#include "Object.h"
#include "ObjectFactory.h"
+#include "StexObject.h"
extern "C"
{
@@ -29,7 +30,7 @@ extern "C"
namespace ObjectFactory
{
- Object * CreateObjectFromLegacyFile(utf8 * path)
+ Object * CreateObjectFromLegacyFile(const utf8 * path)
{
Object * result = nullptr;
@@ -64,6 +65,9 @@ namespace ObjectFactory
case OBJECT_TYPE_PARK_ENTRANCE:
result = new EntranceObject(entry);
break;
+ case OBJECT_TYPE_SCENARIO_TEXT:
+ result = new StexObject(entry);
+ break;
}
return result;
diff --git a/src/object/ObjectFactory.h b/src/object/ObjectFactory.h
index 4d89b7ca6e..1f1ac4647e 100644
--- a/src/object/ObjectFactory.h
+++ b/src/object/ObjectFactory.h
@@ -22,6 +22,6 @@ class Object;
namespace ObjectFactory
{
- Object * CreateObjectFromLegacyFile(utf8 * path);
+ Object * CreateObjectFromLegacyFile(const utf8 * path);
Object * CreateObject(const rct_object_entry &entry);
}
diff --git a/src/object/ObjectRepository.cpp b/src/object/ObjectRepository.cpp
index 203a1ffe79..1eaf17c1d6 100644
--- a/src/object/ObjectRepository.cpp
+++ b/src/object/ObjectRepository.cpp
@@ -17,6 +17,7 @@
#include
#include "../common.h"
+#include "../core/Console.hpp"
#include "../core/FileStream.hpp"
#include "../core/Guard.hpp"
#include "../core/IStream.hpp"
@@ -26,11 +27,14 @@
#include "Object.h"
#include "ObjectFactory.h"
#include "ObjectRepository.h"
+#include "StexObject.h"
extern "C"
{
+ #include "../localisation/localisation.h"
#include "../object.h"
#include "../platform/platform.h"
+ #include "../scenario.h"
}
constexpr uint16 OBJECT_REPOSITORY_VERSION = 6;
@@ -87,6 +91,17 @@ public:
return nullptr;
}
+ Object * LoadObject(const rct_object_entry * objectEntry) override
+ {
+ Object * object = nullptr;
+ const ObjectRepositoryItem * item = FindObject(objectEntry);
+ if (item != nullptr)
+ {
+ object = ObjectFactory::CreateObjectFromLegacyFile(item->Path);
+ }
+ return object;
+ }
+
private:
void ClearItems()
{
@@ -329,4 +344,77 @@ extern "C"
{
IObjectRepository * objRepo = GetObjectRepository();
}
+
+ int object_load_chunk(int groupIndex, rct_object_entry * entry, int * chunkSize)
+ {
+ IObjectRepository * objRepo = GetObjectRepository();
+ Object * object = objRepo->LoadObject(entry);
+ if (object == nullptr)
+ {
+ utf8 objName[9] = { 0 };
+ Memory::Copy(objName, entry->name, 8);
+ Console::Error::WriteFormat("[%s]: Object not found or could not be loaded.", objName);
+ Console::Error::WriteLine();
+ return 0;
+ }
+
+ uint8 objectType = object->GetObjectType();
+ void * * chunkList = object_entry_groups[objectType].chunks;
+ if (groupIndex == -1)
+ {
+ for (groupIndex = 0; chunkList[groupIndex] != (void*)-1; groupIndex++)
+ {
+ if (groupIndex + 1 >= object_entry_group_counts[objectType])
+ {
+ log_error("Object Load failed due to too many objects of a certain type.");
+ delete object;
+ return 0;
+ }
+ }
+ }
+ chunkList[groupIndex] = object->GetLegacyData();
+
+ rct_object_entry_extended * extendedEntry = &object_entry_groups[objectType].entries[groupIndex];
+ Memory::Copy(extendedEntry, object->GetObjectEntry(), sizeof(rct_object_entry));
+ extendedEntry->chunk_size = 0;
+
+ object->Load();
+ return 1;
+ }
+
+ void scenario_translate(scenario_index_entry * scenarioEntry, const rct_object_entry * stexObjectEntry)
+ {
+ rct_string_id localisedStringIds[3];
+ if (language_get_localised_scenario_strings(scenarioEntry->name, localisedStringIds))
+ {
+ if (localisedStringIds[0] != STR_NONE)
+ {
+ String::Set(scenarioEntry->name, sizeof(scenarioEntry->name), language_get_string(localisedStringIds[0]));
+ }
+ if (localisedStringIds[2] != STR_NONE)
+ {
+ String::Set(scenarioEntry->details, sizeof(scenarioEntry->details), language_get_string(localisedStringIds[2]));
+ }
+ }
+ else
+ {
+ // Checks for a scenario string object (possibly for localisation)
+ if ((stexObjectEntry->flags & 0xFF) != 255)
+ {
+ IObjectRepository * objRepo = GetObjectRepository();
+ Object * object = objRepo->LoadObject(stexObjectEntry);
+ if (object != nullptr)
+ {
+ StexObject * stexObject = static_cast(object);
+ const utf8 * scenarioName = stexObject->GetScenarioName();
+ const utf8 * scenarioDetails = stexObject->GetScenarioDetails();
+
+ String::Set(scenarioEntry->name, sizeof(scenarioEntry->name), scenarioName);
+ String::Set(scenarioEntry->details, sizeof(scenarioEntry->details), scenarioDetails);
+
+ delete object;
+ }
+ }
+ }
+ }
}
diff --git a/src/object/ObjectRepository.h b/src/object/ObjectRepository.h
index c686a49de7..f64b6e6b86 100644
--- a/src/object/ObjectRepository.h
+++ b/src/object/ObjectRepository.h
@@ -52,7 +52,8 @@ interface IObjectRepository
{
virtual ~IObjectRepository() { }
- virtual const ObjectRepositoryItem * FindObject(const rct_object_entry * objectEntry) abstract;
+ virtual const ObjectRepositoryItem * FindObject(const rct_object_entry * objectEntry) abstract;
+ virtual Object * LoadObject(const rct_object_entry * objectEntry) abstract;
};
IObjectRepository * GetObjectRepository();
diff --git a/src/object/StexObject.cpp b/src/object/StexObject.cpp
new file mode 100644
index 0000000000..3a8434f732
--- /dev/null
+++ b/src/object/StexObject.cpp
@@ -0,0 +1,77 @@
+#pragma region Copyright (c) 2014-2016 OpenRCT2 Developers
+/*****************************************************************************
+ * OpenRCT2, an open source clone of Roller Coaster Tycoon 2.
+ *
+ * OpenRCT2 is the work of many authors, a full list can be found in contributors.md
+ * For more information, visit https://github.com/OpenRCT2/OpenRCT2
+ *
+ * OpenRCT2 is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * A full copy of the GNU General Public License can be found in licence.txt
+ *****************************************************************************/
+#pragma endregion
+
+#include "../core/IStream.hpp"
+#include "StexObject.h"
+
+extern "C"
+{
+ #include "../localisation/localisation.h"
+}
+
+enum OBJ_STRING_ID
+{
+ OBJ_STRING_ID_SCENARIO_NAME,
+ OBJ_STRING_ID_PARK_NAME,
+ OBJ_STRING_ID_SCENARIO_DETAILS,
+};
+
+void StexObject::ReadLegacy(IStream * stream)
+{
+ _legacyType.scenario_name = stream->ReadValue();
+ _legacyType.park_name = stream->ReadValue();
+ _legacyType.details = stream->ReadValue();
+ _legacyType.var_06 = stream->ReadValue();
+ stream->Seek(1, STREAM_SEEK_CURRENT);
+
+ StringTable.Read(stream, OBJ_STRING_ID_SCENARIO_NAME);
+ StringTable.Read(stream, OBJ_STRING_ID_PARK_NAME);
+ StringTable.Read(stream, OBJ_STRING_ID_SCENARIO_DETAILS);
+}
+
+void StexObject::Load()
+{
+ _legacyType.scenario_name = language_allocate_object_string(GetScenarioName());
+ _legacyType.park_name = language_allocate_object_string(GetParkName());
+ _legacyType.details = language_allocate_object_string(GetScenarioDetails());
+}
+
+void StexObject::Unload()
+{
+ language_free_object_string(_legacyType.scenario_name);
+ language_free_object_string(_legacyType.park_name);
+ language_free_object_string(_legacyType.details);
+}
+
+const utf8 * StexObject::GetName()
+{
+ return GetScenarioName();
+}
+
+const utf8 * StexObject::GetScenarioName()
+{
+ return StringTable.GetString(OBJ_STRING_ID_SCENARIO_NAME);
+}
+
+const utf8 * StexObject::GetScenarioDetails()
+{
+ return StringTable.GetString(OBJ_STRING_ID_SCENARIO_DETAILS);
+}
+
+const utf8 * StexObject::GetParkName()
+{
+ return StringTable.GetString(OBJ_STRING_ID_PARK_NAME);
+}
diff --git a/src/object/StexObject.h b/src/object/StexObject.h
new file mode 100644
index 0000000000..3204cc40db
--- /dev/null
+++ b/src/object/StexObject.h
@@ -0,0 +1,45 @@
+#pragma region Copyright (c) 2014-2016 OpenRCT2 Developers
+/*****************************************************************************
+ * OpenRCT2, an open source clone of Roller Coaster Tycoon 2.
+ *
+ * OpenRCT2 is the work of many authors, a full list can be found in contributors.md
+ * For more information, visit https://github.com/OpenRCT2/OpenRCT2
+ *
+ * OpenRCT2 is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * A full copy of the GNU General Public License can be found in licence.txt
+ *****************************************************************************/
+#pragma endregion
+
+#pragma once
+
+#include "Object.h"
+
+extern "C"
+{
+ #include "../scenario.h"
+}
+
+class StexObject : public Object
+{
+private:
+ rct_stex_entry _legacyType;
+
+public:
+ explicit StexObject(const rct_object_entry &entry) : Object(entry) { };
+
+ void * GetLegacyData() override { return &_legacyType; }
+
+ void ReadLegacy(IStream * stream) override;
+ void Load() override;
+ void Unload() override;
+
+ const utf8 * GetName() override;
+
+ const utf8 * GetScenarioName();
+ const utf8 * GetScenarioDetails();
+ const utf8 * GetParkName();
+};
diff --git a/src/scenario.h b/src/scenario.h
index dd35641e2a..b78057b8e8 100644
--- a/src/scenario.h
+++ b/src/scenario.h
@@ -490,6 +490,8 @@ bool scenario_get_source_desc(const utf8 *name, source_desc *outDesc);
bool scenario_get_source_desc_by_id(uint8 id, source_desc *outDesc);
void scenario_normalise_name(utf8 *name);
+void scenario_translate(scenario_index_entry *scenarioEntry, const rct_object_entry *stexObjectEntry);
+
// RCT1 scenario index map
enum {
SC_UNIDENTIFIED = 255,
diff --git a/src/scenario_list.c b/src/scenario_list.c
index c92a9a520e..29819410d6 100644
--- a/src/scenario_list.c
+++ b/src/scenario_list.c
@@ -36,7 +36,6 @@ static void scenario_list_add(const utf8 *path, uint64 timestamp);
static void scenario_list_sort();
static int scenario_list_sort_by_category(const void *a, const void *b);
static int scenario_list_sort_by_index(const void *a, const void *b);
-static void scenario_translate(scenario_index_entry *scenarioEntry, const rct_object_entry *stexObjectEntry);
static bool scenario_scores_load();
static void scenario_scores_legacy_get_path(utf8 *outPath);
@@ -183,29 +182,6 @@ static void scenario_list_add(const utf8 *path, uint64 timestamp)
scenario_translate(newEntry, &s6Info.entry);
}
-static void scenario_translate(scenario_index_entry *scenarioEntry, const rct_object_entry *stexObjectEntry)
-{
- rct_string_id localisedStringIds[3];
- if (language_get_localised_scenario_strings(scenarioEntry->name, localisedStringIds)) {
- if (localisedStringIds[0] != STR_NONE) {
- safe_strcpy(scenarioEntry->name, language_get_string(localisedStringIds[0]), 64);
- }
- if (localisedStringIds[2] != STR_NONE) {
- safe_strcpy(scenarioEntry->details, language_get_string(localisedStringIds[2]), 256);
- }
- } else {
- // Checks for a scenario string object (possibly for localisation)
- if ((stexObjectEntry->flags & 0xFF) != 255) {
- if (object_get_scenario_text((rct_object_entry*)stexObjectEntry)) {
- rct_stex_entry* stex_entry = gStexTempChunk;
- format_string(scenarioEntry->name, stex_entry->scenario_name, NULL);
- format_string(scenarioEntry->details, stex_entry->details, NULL);
- object_free_scenario_text();
- }
- }
- }
-}
-
void scenario_list_dispose()
{
gScenarioListCapacity = 0;