1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2026-01-15 19:13:07 +01:00

Make object window work with S4s and scenarios

This commit is contained in:
rwjuk
2017-06-30 00:37:41 +01:00
committed by Ted John
parent 214bf3988b
commit ab38c07fb9
16 changed files with 195 additions and 73 deletions

View File

@@ -44,9 +44,9 @@ interface IParkImporter
public:
virtual ~IParkImporter() = default;
virtual park_load_result * Load(const utf8 * path) abstract;
virtual park_load_result * LoadSavedGame(const utf8 * path) abstract;
virtual park_load_result * LoadScenario(const utf8 * path) abstract;
virtual park_load_result * LoadFromStream(IStream * stream, bool isScenario) abstract;
virtual park_load_result * LoadSavedGame(const utf8 * path, bool skipObjectCheck = false) abstract;
virtual park_load_result * LoadScenario(const utf8 * path, bool skipObjectCheck = false) abstract;
virtual park_load_result * LoadFromStream(IStream * stream, bool isScenario, bool skipObjectCheck = false) abstract;
virtual void Import() abstract;
virtual bool GetDetails(scenario_index_entry * dst) abstract;
};

View File

@@ -1119,19 +1119,9 @@ bool game_load_save(const utf8 *path)
// This ensures that the newly loaded save reflects the user's
// 'show real names of guests' option, now that it's a global setting
peep_update_names(gConfigGeneral.show_real_names_of_guests);
return true;
} else {
if (result->error == PARK_LOAD_ERROR_BAD_OBJECTS)
{
// The path needs to be duplicated as it's a const here
// which the window function doesn't like
window_object_load_error_open(strndup(path, strnlen(path, MAX_PATH)), result->object_validity);
} else {
// If loading the SV6 or SV4 failed for a reason other than invalid objects
// the current park state will be corrupted so just go back to the title screen.
title_load();
}
handle_park_load_failure(result, path);
return false;
}
}
@@ -1372,6 +1362,7 @@ void rct2_exit()
bool game_load_save_or_scenario(const utf8 * path)
{
park_load_result* result;
uint32 extension = get_file_extension_type(path);
switch (extension) {
case FILE_EXTENSION_SV4:
@@ -1379,7 +1370,8 @@ bool game_load_save_or_scenario(const utf8 * path)
return game_load_save(path);
case FILE_EXTENSION_SC4:
case FILE_EXTENSION_SC6:
return scenario_load_and_play_from_path(path);
result = scenario_load_and_play_from_path(path);
return (result->error == PARK_LOAD_ERROR_NONE);
}
return false;
}

View File

@@ -121,12 +121,6 @@ enum {
ERROR_TYPE_FILE_LOAD = 255
};
enum PARK_LOAD_ERROR {
PARK_LOAD_ERROR_NONE,
PARK_LOAD_ERROR_BAD_OBJECTS,
PARK_LOAD_ERROR_UNKNOWN = 255
};
typedef void (GAME_COMMAND_POINTER)(sint32* eax, sint32* ebx, sint32* ecx, sint32* edx, sint32* esi, sint32* edi, sint32* ebp);
typedef void (GAME_COMMAND_CALLBACK_POINTER)(sint32 eax, sint32 ebx, sint32 ecx, sint32 edx, sint32 esi, sint32 edi, sint32 ebp);

View File

@@ -19,6 +19,13 @@
#include "object.h"
enum PARK_LOAD_ERROR {
PARK_LOAD_ERROR_NONE,
PARK_LOAD_ERROR_BAD_OBJECTS,
PARK_LOAD_ERROR_INVALID_EXTENSION,
PARK_LOAD_ERROR_UNKNOWN = 255
};
typedef struct object_validity_result
{
uint16 invalid_object_count;

View File

@@ -20,6 +20,7 @@
#include "management/award.h"
#include "management/news_item.h"
#include "management/research.h"
#include "park_load_result_types.h"
#include "rct12.h"
#include "rct2.h"
#include "ride/ride.h"
@@ -1209,8 +1210,8 @@ extern const uint8 gRideCategories[RIDE_TYPE_COUNT];
sint32 vehicle_preference_compare(uint8 rideType, const char * a, const char * b);
bool rideTypeShouldLoseSeparateFlag(const rct_ride_entry *rideEntry);
bool rct1_load_saved_game(const char *path);
bool rct1_load_scenario(const char *path);
park_load_result * rct1_load_saved_game(const char *path);
park_load_result * rct1_load_scenario(const char *path);
colour_t rct1_get_colour(colour_t colour);

View File

@@ -27,6 +27,7 @@
#include "../core/String.hpp"
#include "../core/Util.hpp"
#include "../object/ObjectManager.h"
#include "../object/ObjectRepository.h"
#include "../ParkImporter.h"
#include "../scenario/ScenarioSources.h"
#include "Tables.h"
@@ -142,23 +143,23 @@ public:
}
}
park_load_result* LoadSavedGame(const utf8 * path) override
park_load_result* LoadSavedGame(const utf8 * path, bool skipObjectCheck = false) override
{
auto fs = FileStream(path, FILE_MODE_OPEN);
park_load_result* result = LoadFromStream(&fs, false);
park_load_result* result = LoadFromStream(&fs, false, skipObjectCheck);
_s4Path = path;
return result;
}
park_load_result* LoadScenario(const utf8 * path) override
park_load_result* LoadScenario(const utf8 * path, bool skipObjectCheck = false) override
{
auto fs = FileStream(path, FILE_MODE_OPEN);
park_load_result* result = LoadFromStream(&fs, true);
park_load_result* result = LoadFromStream(&fs, true, skipObjectCheck);
_s4Path = path;
return result;
}
park_load_result* LoadFromStream(IStream * stream, bool isScenario) override
park_load_result* LoadFromStream(IStream * stream, bool isScenario, bool skipObjectCheck = false) override
{
park_load_result* result = Memory::Allocate<park_load_result>(sizeof(park_load_result));
result->error = PARK_LOAD_ERROR_UNKNOWN;
@@ -182,12 +183,28 @@ public:
{
Memory::Copy<void>(&_s4, decodedData.get(), sizeof(rct1_s4));
_s4Path = "";
if (!skipObjectCheck)
{
InitialiseEntryMaps();
CreateAvailableObjectMappings();
object_validity_result* object_result = GetInvalidObjects();
result->object_validity = object_result;
if (object_result->invalid_object_count > 0)
{
result->error = PARK_LOAD_ERROR_BAD_OBJECTS;
}
}
else
{
result->error = PARK_LOAD_ERROR_NONE;
}
}
else
{
throw Exception("Unable to decode park.");
}
result->error = PARK_LOAD_ERROR_NONE;
return result;
}
@@ -309,6 +326,7 @@ private:
Memory::Set(_pathAdditionTypeToEntryMap, 255, sizeof(_pathAdditionTypeToEntryMap));
Memory::Set(_sceneryThemeTypeToEntryMap, 255, sizeof(_sceneryThemeTypeToEntryMap));
InitialiseEntryMaps();
uint16 mapSize = _s4.map_size == 0 ? 128 : _s4.map_size;
// Do map initialisation, same kind of stuff done when loading scenario editor
@@ -319,6 +337,18 @@ private:
gS6Info.category = SCENARIO_CATEGORY_OTHER;
}
void InitialiseEntryMaps()
{
Memory::Set(_rideTypeToRideEntryMap, 255, sizeof(_rideTypeToRideEntryMap));
Memory::Set(_vehicleTypeToRideEntryMap, 255, sizeof(_vehicleTypeToRideEntryMap));
Memory::Set(_smallSceneryTypeToEntryMap, 255, sizeof(_smallSceneryTypeToEntryMap));
Memory::Set(_largeSceneryTypeToEntryMap, 255, sizeof(_largeSceneryTypeToEntryMap));
Memory::Set(_wallTypeToEntryMap, 255, sizeof(_wallTypeToEntryMap));
Memory::Set(_pathTypeToEntryMap, 255, sizeof(_pathTypeToEntryMap));
Memory::Set(_pathAdditionTypeToEntryMap, 255, sizeof(_pathAdditionTypeToEntryMap));
Memory::Set(_sceneryThemeTypeToEntryMap, 255, sizeof(_sceneryThemeTypeToEntryMap));
}
/**
* Scans the map and research list for all the object types used and builds lists and
* lookup tables for converting from hard coded RCT1 object types to dynamic object entries.
@@ -1725,6 +1755,73 @@ private:
}
}
object_validity_result* GetInvalidObjects()
{
object_validity_result* result = Memory::Allocate<object_validity_result>(sizeof(object_validity_result));
uint16 invalidObjectCount = 0;
rct_object_entry * * invalidEntries = Memory::AllocateArray<rct_object_entry *>(OBJECT_ENTRY_COUNT);
result->invalid_object_count = invalidObjectCount;
result->invalid_objects = invalidEntries;
GetInvalidObjects(OBJECT_TYPE_RIDE, _rideEntries.GetEntries(), *result);
GetInvalidObjects(OBJECT_TYPE_SMALL_SCENERY, _smallSceneryEntries.GetEntries(), *result);
GetInvalidObjects(OBJECT_TYPE_LARGE_SCENERY, _largeSceneryEntries.GetEntries(), *result);
GetInvalidObjects(OBJECT_TYPE_WALLS, _wallEntries.GetEntries(), *result);
GetInvalidObjects(OBJECT_TYPE_PATHS, _pathEntries.GetEntries(), *result);
GetInvalidObjects(OBJECT_TYPE_PATH_BITS, _pathAdditionEntries.GetEntries(), *result);
GetInvalidObjects(OBJECT_TYPE_SCENERY_SETS, _sceneryGroupEntries.GetEntries(), *result);
GetInvalidObjects(OBJECT_TYPE_BANNERS, std::vector<const char *>({
"BN1 ",
"BN2 ",
"BN3 ",
"BN4 ",
"BN5 ",
"BN6 ",
"BN7 ",
"BN8 ",
"BN9 "
}), *result);
GetInvalidObjects(OBJECT_TYPE_PARK_ENTRANCE, std::vector<const char *>({ "PKENT1 " }), *result);
GetInvalidObjects(OBJECT_TYPE_WATER, _waterEntry.GetEntries(), *result);
return result;
}
void GetInvalidObjects(uint8 objectType, const std::vector<const char *> &entries, object_validity_result &result)
{
IObjectRepository * objectRepository = GetObjectRepository();
for (const char * objectName : entries)
{
rct_object_entry entry;
entry.flags = 0x00008000 + objectType;
Memory::Copy(entry.name, objectName, 8);
entry.checksum = 0;
const ObjectRepositoryItem * ori = nullptr;
ori = objectRepository->FindObject(&entry);
if (ori == nullptr)
{
rct_object_entry * invalid_entry = Memory::Allocate<rct_object_entry>(sizeof(rct_object_entry));
invalid_entry->flags = entry.flags;
Memory::Copy(invalid_entry->name, objectName, 8);
result.invalid_objects[result.invalid_object_count++] = invalid_entry;
}
else
{
Object * object = objectRepository->LoadObject(ori);
if (object == nullptr && objectType != OBJECT_TYPE_SCENERY_SETS)
{
rct_object_entry * invalid_entry = Memory::Allocate<rct_object_entry>(sizeof(rct_object_entry));
invalid_entry->flags = entry.flags;
Memory::Copy(invalid_entry->name, objectName, 8);
result.invalid_objects[result.invalid_object_count++] = invalid_entry;
}
SafeFree(object);
}
}
}
void ImportMapElements()
{
Memory::Copy(gMapElements, _s4.map_elements, RCT1_MAX_MAP_ELEMENTS * sizeof(rct_map_element));
@@ -2568,37 +2665,44 @@ IParkImporter * ParkImporter::CreateS4()
/////////////////////////////////////////
extern "C"
{
bool rct1_load_saved_game(const utf8 * path)
park_load_result* rct1_load_saved_game(const utf8 * path)
{
bool result;
park_load_result* result = {};
auto s4Importer = new S4Importer();
try
{
s4Importer->LoadSavedGame(path);
s4Importer->Import();
result = true;
result = s4Importer->LoadSavedGame(path);
if (result->error == PARK_LOAD_ERROR_NONE)
{
s4Importer->Import();
}
} catch (const Exception &)
{
result = false;
result = {};
result->error = PARK_LOAD_ERROR_UNKNOWN;
}
delete s4Importer;
return result;
}
bool rct1_load_scenario(const utf8 * path)
park_load_result* rct1_load_scenario(const utf8 * path)
{
bool result;
park_load_result* result = {};
auto s4Importer = new S4Importer();
try
{
s4Importer->LoadScenario(path);
s4Importer->Import();
result = true;
result = s4Importer->LoadSavedGame(path);
if (result->error == PARK_LOAD_ERROR_NONE)
{
s4Importer->Import();
}
} catch (const Exception &)
{
result = false;
result = {};
result->error = PARK_LOAD_ERROR_UNKNOWN;
}
delete s4Importer;
return result;

View File

@@ -339,9 +339,14 @@ bool rct2_open_file(const char *path)
}
} else if (_stricmp(extension, "sc6") == 0) {
// TODO scenario install
if (scenario_load_and_play_from_path(path)) {
park_load_result *result = scenario_load_and_play_from_path(path);
if (result->error == PARK_LOAD_ERROR_NONE) {
return true;
}
else {
handle_park_load_failure(result, path);
return false;
}
} else if (_stricmp(extension, "td6") == 0 || _stricmp(extension, "td4") == 0) {
// TODO track design install
return true;

View File

@@ -98,25 +98,25 @@ public:
}
}
park_load_result* LoadSavedGame(const utf8 * path) override
park_load_result* LoadSavedGame(const utf8 * path, bool skipObjectCheck = false) override
{
auto fs = FileStream(path, FILE_MODE_OPEN);
park_load_result* result = LoadFromStream(&fs, false);
park_load_result* result = LoadFromStream(&fs, false, skipObjectCheck);
_s6Path = path;
return result;
}
park_load_result* LoadScenario(const utf8 * path) override
park_load_result* LoadScenario(const utf8 * path, bool skipObjectCheck = false) override
{
auto fs = FileStream(path, FILE_MODE_OPEN);
park_load_result* result = LoadFromStream(&fs, true);
park_load_result* result = LoadFromStream(&fs, true, skipObjectCheck);
_s6Path = path;
return result;
}
park_load_result* LoadFromStream(IStream * stream, bool isScenario) override
park_load_result* LoadFromStream(IStream * stream, bool isScenario, bool skipObjectCheck = false) override
{
park_load_result* result = Memory::Allocate<park_load_result>(sizeof(park_load_result));
result->error = PARK_LOAD_ERROR_UNKNOWN;
@@ -487,14 +487,14 @@ extern "C"
* rct2: 0x00676053
* scenario (ebx)
*/
park_load_result *scenario_load(const char * path)
park_load_result* scenario_load(const char * path)
{
park_load_result* result = {};
auto s6Importer = new S6Importer(GetObjectRepository(), GetObjectManager());
try
{
result = s6Importer->LoadScenario(path);
if (result->error != PARK_LOAD_ERROR_NONE)
if (result->error == PARK_LOAD_ERROR_NONE)
{
s6Importer->Import();

View File

@@ -322,7 +322,7 @@ private:
try
{
auto s4Importer = std::unique_ptr<IParkImporter>(ParkImporter::CreateS4());
s4Importer->LoadScenario(path.c_str());
s4Importer->LoadScenario(path.c_str(), true);
if (s4Importer->GetDetails(entry))
{
String::Set(entry->path, sizeof(entry->path), path.c_str());

View File

@@ -88,31 +88,29 @@ money32 gScenarioCompanyValueRecord;
static sint32 scenario_create_ducks();
static void scenario_objective_check();
sint32 scenario_load_and_play_from_path(const char *path)
park_load_result* scenario_load_and_play_from_path(const char *path)
{
window_close_construction_windows();
uint32 extension = get_file_extension_type(path);
park_load_result* result;
park_load_result* result = malloc(sizeof(park_load_result));
if (extension == FILE_EXTENSION_SC6) {
result = scenario_load(path);
if (result->error != PARK_LOAD_ERROR_NONE)
{
if (result->error == PARK_LOAD_ERROR_BAD_OBJECTS)
{
// The path needs to be duplicated as it's a const here
// which the window function doesn't like
window_object_load_error_open(strndup(path, strnlen(path, MAX_PATH)), result->object_validity);
}
return 0;
return result;
}
}
else if (extension == FILE_EXTENSION_SC4) {
if (!rct1_load_scenario(path))
return 0;
result = rct1_load_scenario(path);
if (result->error != PARK_LOAD_ERROR_NONE)
{
return result;
}
}
else {
return 0;
result->error = PARK_LOAD_ERROR_INVALID_EXTENSION;
return result;
}
reset_sprite_spatial_index();
@@ -141,8 +139,7 @@ sint32 scenario_load_and_play_from_path(const char *path)
// This ensures that the newly loaded scenario reflects the user's
// 'show real names of guests' option, now that it's a global setting
peep_update_names(gConfigGeneral.show_real_names_of_guests);
return 1;
return result;
}
void scenario_begin()

View File

@@ -391,7 +391,7 @@ extern uint32 gLastAutoSaveUpdate;
extern const char *_scenarioFileName;
park_load_result *scenario_load(const char *path);
sint32 scenario_load_and_play_from_path(const char *path);
park_load_result *scenario_load_and_play_from_path(const char *path);
void scenario_begin();
void scenario_update();

View File

@@ -18,8 +18,10 @@
#include <time.h>
#include "../common.h"
#include "../core/Guard.hpp"
#include "../interface/window.h"
#include "../localisation/localisation.h"
#include "../platform/platform.h"
#include "../title/TitleScreen.h"
#include "util.h"
#include "zlib.h"
@@ -547,3 +549,19 @@ size_t strcatftime(char * buffer, size_t bufferSize, const char * format, const
}
return 0;
}
void handle_park_load_failure(park_load_result* result, const utf8* path)
{
if (result->error == PARK_LOAD_ERROR_BAD_OBJECTS)
{
// The path needs to be duplicated as it's a const here
// which the window function doesn't like
window_object_load_error_open(strndup(path, strnlen(path, MAX_PATH)), result->object_validity);
}
else if (result->error != PARK_LOAD_ERROR_NONE) {
// If loading the SV6 or SV4 failed for a reason other than invalid objects
// the current park state will be corrupted so just go back to the title screen.
title_load();
}
SafeFree(result);
}

View File

@@ -19,6 +19,7 @@
#include <time.h>
#include "../common.h"
#include "../park_load_result_types.h"
sint32 squaredmetres_to_squaredfeet(sint32 squaredMetres);
sint32 metres_to_feet(sint32 metres);
@@ -65,4 +66,5 @@ money32 add_clamp_money32(money32 value, money32 value_to_add);
size_t strcatftime(char * buffer, size_t bufferSize, const char * format, const struct tm * tp);
void handle_park_load_failure(park_load_result* result, const utf8* path);
#endif

View File

@@ -21,6 +21,7 @@
#include "../interface/window.h"
#include "../localisation/localisation.h"
#include "../network/network.h"
#include "../platform/platform.h"
#include "../sprites.h"
#include "../title/TitleScreen.h"
#include "../util/util.h"
@@ -164,11 +165,13 @@ static void window_server_start_close(rct_window *w)
static void window_server_start_scenarioselect_callback(const utf8 *path)
{
park_load_result* result;
network_set_password(_password);
if (scenario_load_and_play_from_path(path)) {
result = scenario_load_and_play_from_path(path);
if (result->error == PARK_LOAD_ERROR_NONE) {
network_begin_server(gConfigNetwork.default_port, gConfigNetwork.listen_address);
} else {
title_load();
handle_park_load_failure(result, path);
}
}

View File

@@ -24,6 +24,7 @@
#include "../localisation/localisation.h"
#include "../sprites.h"
#include "../title/TitleScreen.h"
#include "../util/util.h"
#include "dropdown.h"
enum {
@@ -128,9 +129,8 @@ void window_title_menu_open()
static void window_title_menu_scenarioselect_callback(const utf8 *path)
{
if (!scenario_load_and_play_from_path(path)) {
title_load();
}
park_load_result *result = scenario_load_and_play_from_path(path);
handle_park_load_failure(result, path);
}
static void window_title_menu_mouseup(rct_window *w, rct_widgetindex widgetIndex)

View File

@@ -519,9 +519,8 @@ static void window_top_toolbar_mousedown(rct_widgetindex widgetIndex, rct_window
static void window_top_toolbar_scenarioselect_callback(const utf8 *path)
{
if (!scenario_load_and_play_from_path(path)) {
title_load();
}
park_load_result *result = scenario_load_and_play_from_path(path);
handle_park_load_failure(result, path);
}
/**