mirror of https://github.com/OpenRCT2/OpenRCT2.git
Merge pull request #3528 from IntelOrca/refactor/s6importer
Add S6Importer and S6Exporter
This commit is contained in:
commit
0570ec27ff
|
@ -10,7 +10,6 @@
|
|||
008BF72A1CDAA5C30019A2AD /* track_design_index.c in Sources */ = {isa = PBXBuildFile; fileRef = 008BF7261CDAA5C30019A2AD /* track_design_index.c */; };
|
||||
008BF72B1CDAA5C30019A2AD /* track_design_save.c in Sources */ = {isa = PBXBuildFile; fileRef = 008BF7271CDAA5C30019A2AD /* track_design_save.c */; };
|
||||
008BF72C1CDAA5C30019A2AD /* track_design.c in Sources */ = {isa = PBXBuildFile; fileRef = 008BF7281CDAA5C30019A2AD /* track_design.c */; };
|
||||
C61FAAE21CD1643A0010C9D8 /* paint_surface.c in Sources */ = {isa = PBXBuildFile; fileRef = C61FAAE01CD1643A0010C9D8 /* paint_surface.c */; };
|
||||
C650B2191CCABBDD00B4D91C /* S4Importer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C650B2151CCABBDD00B4D91C /* S4Importer.cpp */; };
|
||||
C650B21A1CCABBDD00B4D91C /* tables.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C650B2171CCABBDD00B4D91C /* tables.cpp */; };
|
||||
C650B21C1CCABC4400B4D91C /* ConvertCommand.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C650B21B1CCABC4400B4D91C /* ConvertCommand.cpp */; };
|
||||
|
@ -104,6 +103,8 @@
|
|||
C686F9541CDBC3B7009F9BFC /* submarine_ride.c in Sources */ = {isa = PBXBuildFile; fileRef = C686F9091CDBC3B7009F9BFC /* submarine_ride.c */; };
|
||||
C686F9551CDBC3B7009F9BFC /* water_coaster.c in Sources */ = {isa = PBXBuildFile; fileRef = C686F90A1CDBC3B7009F9BFC /* water_coaster.c */; };
|
||||
C686F9581CDBC4C7009F9BFC /* vehicle_paint.c in Sources */ = {isa = PBXBuildFile; fileRef = C686F9561CDBC4C7009F9BFC /* vehicle_paint.c */; };
|
||||
C6B5A7D41CDFE4CB00C9C006 /* S6Exporter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C6B5A7D01CDFE4CB00C9C006 /* S6Exporter.cpp */; };
|
||||
C6B5A7D51CDFE4CB00C9C006 /* S6Importer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C6B5A7D21CDFE4CB00C9C006 /* S6Importer.cpp */; };
|
||||
D41B73EF1C2101890080A7B9 /* libcurl.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = D41B73EE1C2101890080A7B9 /* libcurl.tbd */; };
|
||||
D41B73F11C21018C0080A7B9 /* libssl.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = D41B73F01C21018C0080A7B9 /* libssl.tbd */; };
|
||||
D41B741D1C210A7A0080A7B9 /* libiconv.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = D41B741C1C210A7A0080A7B9 /* libiconv.tbd */; };
|
||||
|
@ -326,8 +327,6 @@
|
|||
008BF7271CDAA5C30019A2AD /* track_design_save.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = track_design_save.c; sourceTree = "<group>"; };
|
||||
008BF7281CDAA5C30019A2AD /* track_design.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = track_design.c; sourceTree = "<group>"; };
|
||||
008BF7291CDAA5C30019A2AD /* track_design.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = track_design.h; sourceTree = "<group>"; };
|
||||
C61FAAE01CD1643A0010C9D8 /* paint_surface.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = paint_surface.c; sourceTree = "<group>"; };
|
||||
C61FAAE11CD1643A0010C9D8 /* paint_surface.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = paint_surface.h; sourceTree = "<group>"; };
|
||||
C650B2151CCABBDD00B4D91C /* S4Importer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = S4Importer.cpp; sourceTree = "<group>"; };
|
||||
C650B2161CCABBDD00B4D91C /* S4Importer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = S4Importer.h; sourceTree = "<group>"; };
|
||||
C650B2171CCABBDD00B4D91C /* tables.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = tables.cpp; sourceTree = "<group>"; };
|
||||
|
@ -429,6 +428,10 @@
|
|||
C686F90A1CDBC3B7009F9BFC /* water_coaster.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = water_coaster.c; sourceTree = "<group>"; };
|
||||
C686F9561CDBC4C7009F9BFC /* vehicle_paint.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = vehicle_paint.c; sourceTree = "<group>"; };
|
||||
C686F9571CDBC4C7009F9BFC /* vehicle_paint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vehicle_paint.h; sourceTree = "<group>"; };
|
||||
C6B5A7D01CDFE4CB00C9C006 /* S6Exporter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = S6Exporter.cpp; sourceTree = "<group>"; };
|
||||
C6B5A7D11CDFE4CB00C9C006 /* S6Exporter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = S6Exporter.h; sourceTree = "<group>"; };
|
||||
C6B5A7D21CDFE4CB00C9C006 /* S6Importer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = S6Importer.cpp; sourceTree = "<group>"; };
|
||||
C6B5A7D31CDFE4CB00C9C006 /* S6Importer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = S6Importer.h; sourceTree = "<group>"; };
|
||||
D41B73EE1C2101890080A7B9 /* libcurl.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libcurl.tbd; path = usr/lib/libcurl.tbd; sourceTree = SDKROOT; };
|
||||
D41B73F01C21018C0080A7B9 /* libssl.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libssl.tbd; path = usr/lib/libssl.tbd; sourceTree = SDKROOT; };
|
||||
D41B741C1C210A7A0080A7B9 /* libiconv.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libiconv.tbd; path = usr/lib/libiconv.tbd; sourceTree = SDKROOT; };
|
||||
|
@ -981,6 +984,18 @@
|
|||
path = water;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
C6B5A7CF1CDFE4CB00C9C006 /* rct2 */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
C6B5A7D01CDFE4CB00C9C006 /* S6Exporter.cpp */,
|
||||
C6B5A7D11CDFE4CB00C9C006 /* S6Exporter.h */,
|
||||
C6B5A7D21CDFE4CB00C9C006 /* S6Importer.cpp */,
|
||||
C6B5A7D31CDFE4CB00C9C006 /* S6Importer.h */,
|
||||
);
|
||||
name = rct2;
|
||||
path = src/rct2;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D41B72431C21015A0080A7B9 /* Sources */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -996,6 +1011,7 @@
|
|||
D442715B1CC81B3200D84D28 /* peep */,
|
||||
D44271601CC81B3200D84D28 /* platform */,
|
||||
C650B2141CCABBDD00B4D91C /* rct1 */,
|
||||
C6B5A7CF1CDFE4CB00C9C006 /* rct2 */,
|
||||
D442716E1CC81B3200D84D28 /* ride */,
|
||||
D44271881CC81B3200D84D28 /* util */,
|
||||
D442718E1CC81B3200D84D28 /* windows */,
|
||||
|
@ -1874,6 +1890,7 @@
|
|||
D442720E1CC81B3200D84D28 /* rect.c in Sources */,
|
||||
C686F9171CDBC3B7009F9BFC /* lim_launched_roller_coaster.c in Sources */,
|
||||
C686F9101CDBC3B7009F9BFC /* giga_coaster.c in Sources */,
|
||||
C6B5A7D41CDFE4CB00C9C006 /* S6Exporter.cpp in Sources */,
|
||||
D44272351CC81B3200D84D28 /* twitch.cpp in Sources */,
|
||||
D44272691CC81B3200D84D28 /* loadsave.c in Sources */,
|
||||
D44272061CC81B3200D84D28 /* textinputbuffer.c in Sources */,
|
||||
|
@ -1973,6 +1990,7 @@
|
|||
D442727A1CC81B3200D84D28 /* research.c in Sources */,
|
||||
D442722E1CC81B3200D84D28 /* award.c in Sources */,
|
||||
D44272861CC81B3200D84D28 /* staff_fire_prompt.c in Sources */,
|
||||
C6B5A7D51CDFE4CB00C9C006 /* S6Importer.cpp in Sources */,
|
||||
D44272221CC81B3200D84D28 /* widget.c in Sources */,
|
||||
D44271F71CC81B3200D84D28 /* mixer.cpp in Sources */,
|
||||
D442723D1CC81B3200D84D28 /* osx.m in Sources */,
|
||||
|
|
|
@ -112,6 +112,8 @@
|
|||
<ClCompile Include="src\rct1\S4Importer.cpp" />
|
||||
<ClCompile Include="src\rct1\Tables.cpp" />
|
||||
<ClCompile Include="src\rct2.c" />
|
||||
<ClCompile Include="src\rct2\S6Exporter.cpp" />
|
||||
<ClCompile Include="src\rct2\S6Importer.cpp" />
|
||||
<ClCompile Include="src\ride\cable_lift.c" />
|
||||
<ClCompile Include="src\ride\coaster\air_powered_vertical_coaster.c" />
|
||||
<ClCompile Include="src\ride\coaster\bobsleigh_coaster.c" />
|
||||
|
@ -370,6 +372,8 @@
|
|||
<ClInclude Include="src\rct1\Tables.h" />
|
||||
<ClInclude Include="src\rct1\S4Importer.h" />
|
||||
<ClInclude Include="src\rct2.h" />
|
||||
<ClInclude Include="src\rct2\S6Exporter.h" />
|
||||
<ClInclude Include="src\rct2\S6Importer.h" />
|
||||
<ClInclude Include="src\ride\cable_lift.h" />
|
||||
<ClInclude Include="src\ride\ride.h" />
|
||||
<ClInclude Include="src\ride\ride_data.h" />
|
||||
|
|
|
@ -270,6 +270,8 @@
|
|||
<ClCompile Include="src\ride\gentle\space_rings.c" />
|
||||
<ClCompile Include="src\ride\gentle\spiral_slide.c" />
|
||||
<ClCompile Include="src\ride\vehicle_paint.c" />
|
||||
<ClCompile Include="src\rct2\S6Importer.cpp" />
|
||||
<ClCompile Include="src\rct2\S6Exporter.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="resources\resource.h" />
|
||||
|
@ -382,6 +384,8 @@
|
|||
<ClInclude Include="src\world\sprite.h" />
|
||||
<ClInclude Include="src\world\water.h" />
|
||||
<ClInclude Include="src\ride\vehicle_paint.h" />
|
||||
<ClInclude Include="src\rct2\S6Importer.h" />
|
||||
<ClInclude Include="src\rct2\S6Exporter.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="resources\OpenRCT2.rc" />
|
||||
|
|
|
@ -320,8 +320,8 @@
|
|||
#define RCT2_ADDRESS_CURRENT_MONEY_ENCRYPTED 0x013587F8
|
||||
#define RCT2_ADDRESS_CURRENT_INTEREST_RATE 0x0135934A
|
||||
#define RCT2_ADDRESS_SAME_PRICE_THROUGHOUT 0x01358838
|
||||
#define RCT2_ADDRESS_LAST_ENTRANCE_STYLE 0x01358840
|
||||
#define RCT2_ADDRESS_SAME_PRICE_THROUGHOUT_EXTENDED 0x0135934C
|
||||
|
||||
#define RCT2_ADDRESS_GUEST_INITIAL_CASH 0x013580F4
|
||||
#define RCT2_ADDRESS_GUEST_INITIAL_HAPPINESS 0x013580E9
|
||||
#define RCT2_ADDRESS_GUEST_INITIAL_HUNGER 0x013580F6
|
||||
|
|
147
src/game.c
147
src/game.c
|
@ -733,75 +733,6 @@ void game_convert_strings_to_rct2(rct_s6_data *s6)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* rct2: 0x00675E1B
|
||||
*/
|
||||
int game_load_sv6(SDL_RWops* rw)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
if (!sawyercoding_validate_checksum(rw)) {
|
||||
log_error("invalid checksum");
|
||||
|
||||
gErrorType = ERROR_TYPE_FILE_LOAD;
|
||||
gGameCommandErrorTitle = STR_FILE_CONTAINS_INVALID_DATA;
|
||||
return 0;
|
||||
}
|
||||
|
||||
rct_s6_header *s6Header = (rct_s6_header*)0x009E34E4;
|
||||
rct_s6_info *s6Info = (rct_s6_info*)0x0141F570;
|
||||
|
||||
// Read first chunk
|
||||
sawyercoding_read_chunk(rw, (uint8*)s6Header);
|
||||
if (s6Header->type == S6_TYPE_SAVEDGAME) {
|
||||
// Read packed objects
|
||||
if (s6Header->num_packed_objects > 0) {
|
||||
j = 0;
|
||||
for (i = 0; i < s6Header->num_packed_objects; i++)
|
||||
j += object_load_packed(rw);
|
||||
if (j > 0)
|
||||
object_list_load();
|
||||
}
|
||||
}
|
||||
|
||||
uint8 load_success = object_read_and_load_entries(rw);
|
||||
|
||||
// Read flags (16 bytes)
|
||||
sawyercoding_read_chunk(rw, (uint8*)RCT2_ADDRESS_CURRENT_MONTH_YEAR);
|
||||
|
||||
// Read map elements
|
||||
memset((void*)RCT2_ADDRESS_MAP_ELEMENTS, 0, MAX_MAP_ELEMENTS * sizeof(rct_map_element));
|
||||
sawyercoding_read_chunk(rw, (uint8*)RCT2_ADDRESS_MAP_ELEMENTS);
|
||||
|
||||
// Read game data, including sprites
|
||||
sawyercoding_read_chunk(rw, (uint8*)0x010E63B8);
|
||||
|
||||
if (!load_success){
|
||||
set_load_objects_fail_reason();
|
||||
if (gInputFlags & INPUT_FLAG_5){
|
||||
//call 0x0040705E Sets cursor position and something else. Calls maybe wind func 8 probably pointless
|
||||
gInputFlags &= ~INPUT_FLAG_5;
|
||||
}
|
||||
|
||||
return 0;//This never gets called
|
||||
}
|
||||
|
||||
// The rest is the same as in scenario_load
|
||||
reset_loaded_objects();
|
||||
map_update_tile_pointers();
|
||||
reset_0x69EBE4();
|
||||
openrct2_reset_object_tween_locations();
|
||||
game_convert_strings_to_utf8();
|
||||
game_fix_save_vars(); // OpenRCT2 fix broken save games
|
||||
|
||||
// #2407: Resetting screen time to not open a save prompt shortly after loading a park.
|
||||
gScreenAge = 0;
|
||||
|
||||
gLastAutoSaveTick = SDL_GetTicks();
|
||||
return 1;
|
||||
}
|
||||
|
||||
// OpenRCT2 workaround to recalculate some values which are saved redundantly in the save to fix corrupted files.
|
||||
// For example recalculate guest count by looking at all the guests instead of trusting the value in the file.
|
||||
void game_fix_save_vars() {
|
||||
|
@ -835,84 +766,6 @@ void game_fix_save_vars() {
|
|||
}
|
||||
}
|
||||
|
||||
// Load game state for multiplayer
|
||||
int game_load_network(SDL_RWops* rw)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
rct_s6_header *s6Header = (rct_s6_header*)0x009E34E4;
|
||||
rct_s6_info *s6Info = (rct_s6_info*)0x0141F570;
|
||||
|
||||
// Read first chunk
|
||||
sawyercoding_read_chunk(rw, (uint8*)s6Header);
|
||||
if (s6Header->type == S6_TYPE_SAVEDGAME) {
|
||||
// Read packed objects
|
||||
if (s6Header->num_packed_objects > 0) {
|
||||
j = 0;
|
||||
for (i = 0; i < s6Header->num_packed_objects; i++)
|
||||
j += object_load_packed(rw);
|
||||
if (j > 0)
|
||||
object_list_load();
|
||||
}
|
||||
}
|
||||
|
||||
uint8 load_success = object_read_and_load_entries(rw);
|
||||
|
||||
// Read flags (16 bytes)
|
||||
sawyercoding_read_chunk(rw, (uint8*)RCT2_ADDRESS_CURRENT_MONTH_YEAR);
|
||||
|
||||
// Read map elements
|
||||
memset((void*)RCT2_ADDRESS_MAP_ELEMENTS, 0, MAX_MAP_ELEMENTS * sizeof(rct_map_element));
|
||||
sawyercoding_read_chunk(rw, (uint8*)RCT2_ADDRESS_MAP_ELEMENTS);
|
||||
|
||||
// Read game data, including sprites
|
||||
sawyercoding_read_chunk(rw, (uint8*)0x010E63B8);
|
||||
|
||||
// Read checksum
|
||||
uint32 checksum;
|
||||
SDL_RWread(rw, &checksum, sizeof(uint32), 1);
|
||||
|
||||
// Read other data not in normal save files
|
||||
gGamePaused = SDL_ReadLE32(rw);
|
||||
_guestGenerationProbability = SDL_ReadLE32(rw);
|
||||
_suggestedGuestMaximum = SDL_ReadLE32(rw);
|
||||
gCheatsSandboxMode = SDL_ReadU8(rw);
|
||||
gCheatsDisableClearanceChecks = SDL_ReadU8(rw);
|
||||
gCheatsDisableSupportLimits = SDL_ReadU8(rw);
|
||||
gCheatsDisableTrainLengthLimit = SDL_ReadU8(rw);
|
||||
gCheatsShowAllOperatingModes = SDL_ReadU8(rw);
|
||||
gCheatsShowVehiclesFromOtherTrackTypes = SDL_ReadU8(rw);
|
||||
gCheatsFastLiftHill = SDL_ReadU8(rw);
|
||||
gCheatsDisableBrakesFailure = SDL_ReadU8(rw);
|
||||
gCheatsDisableAllBreakdowns = SDL_ReadU8(rw);
|
||||
gCheatsUnlockAllPrices = SDL_ReadU8(rw);
|
||||
gCheatsBuildInPauseMode = SDL_ReadU8(rw);
|
||||
gCheatsIgnoreRideIntensity = SDL_ReadU8(rw);
|
||||
gCheatsDisableVandalism = SDL_ReadU8(rw);
|
||||
gCheatsDisableLittering = SDL_ReadU8(rw);
|
||||
gCheatsNeverendingMarketing = SDL_ReadU8(rw);
|
||||
gCheatsFreezeClimate = SDL_ReadU8(rw);
|
||||
|
||||
if (!load_success){
|
||||
set_load_objects_fail_reason();
|
||||
if (gInputFlags & INPUT_FLAG_5){
|
||||
//call 0x0040705E Sets cursor position and something else. Calls maybe wind func 8 probably pointless
|
||||
gInputFlags &= ~INPUT_FLAG_5;
|
||||
}
|
||||
|
||||
return 0;//This never gets called
|
||||
}
|
||||
|
||||
// The rest is the same as in scenario load and play
|
||||
reset_loaded_objects();
|
||||
map_update_tile_pointers();
|
||||
reset_0x69EBE4();
|
||||
openrct2_reset_object_tween_locations();
|
||||
game_convert_strings_to_utf8();
|
||||
gLastAutoSaveTick = SDL_GetTicks();
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* rct2: 0x00675E1B
|
||||
|
|
|
@ -1668,3 +1668,26 @@ sint16 get_height_marker_offset()
|
|||
// Height labels in metres
|
||||
return 2 * 256;
|
||||
}
|
||||
|
||||
void viewport_set_saved_view()
|
||||
{
|
||||
sint16 viewX = 0;
|
||||
sint16 viewY = 0;
|
||||
uint8 viewZoom = 0;
|
||||
uint8 viewRotation = 0;
|
||||
|
||||
rct_window * w = window_get_main();
|
||||
if (w != NULL) {
|
||||
rct_viewport *viewport = w->viewport;
|
||||
|
||||
viewX = viewport->view_width / 2 + viewport->view_x;
|
||||
viewY = viewport->view_height / 2 + viewport->view_y;
|
||||
viewZoom = viewport->zoom;
|
||||
viewRotation = get_current_rotation();
|
||||
}
|
||||
|
||||
gSavedViewX = viewX;
|
||||
gSavedViewY = viewY;
|
||||
gSavedViewZoom = viewZoom;
|
||||
gSavedViewRotation = viewRotation;
|
||||
}
|
||||
|
|
|
@ -148,4 +148,6 @@ void screen_get_map_xy_side_with_z(sint16 screenX, sint16 screenY, sint16 z, sin
|
|||
uint8 get_current_rotation();
|
||||
sint16 get_height_marker_offset();
|
||||
|
||||
void viewport_set_saved_view();
|
||||
|
||||
#endif
|
||||
|
|
|
@ -49,6 +49,8 @@ typedef struct {
|
|||
|
||||
#define MAX_NEWS_ITEMS 60
|
||||
|
||||
extern rct_news_item *gNewsItems;
|
||||
|
||||
void news_item_init_queue();
|
||||
void news_item_update_current();
|
||||
void news_item_close_current();
|
||||
|
|
|
@ -104,7 +104,8 @@ extern void *gLastLoadedObjectChunkData;
|
|||
int object_load_entry(const utf8 *path, rct_object_entry *outEntry);
|
||||
void object_list_load();
|
||||
void set_load_objects_fail_reason();
|
||||
int object_read_and_load_entries(SDL_RWops* rw);
|
||||
bool object_read_and_load_entries(SDL_RWops* rw);
|
||||
bool object_load_entries(rct_object_entry* entries);
|
||||
int object_load_packed(SDL_RWops* rw);
|
||||
void object_unload_all();
|
||||
|
||||
|
|
|
@ -530,28 +530,32 @@ void set_load_objects_fail_reason()
|
|||
*
|
||||
* rct2: 0x006AA0C6
|
||||
*/
|
||||
int object_read_and_load_entries(SDL_RWops* rw)
|
||||
bool object_read_and_load_entries(SDL_RWops* rw)
|
||||
{
|
||||
object_unload_all();
|
||||
|
||||
int i, j;
|
||||
rct_object_entry *entries;
|
||||
// Read all the object entries
|
||||
rct_object_entry *entries = malloc(OBJECT_ENTRY_COUNT * sizeof(rct_object_entry));
|
||||
sawyercoding_read_chunk(rw, (uint8*)entries);
|
||||
bool result = object_load_entries(entries);
|
||||
free(entries);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool object_load_entries(rct_object_entry* entries)
|
||||
{
|
||||
log_verbose("loading required objects");
|
||||
|
||||
// Read all the object entries
|
||||
entries = malloc(OBJECT_ENTRY_COUNT * sizeof(rct_object_entry));
|
||||
sawyercoding_read_chunk(rw, (uint8*)entries);
|
||||
|
||||
uint8 load_fail = 0;
|
||||
bool loadFailed = false;
|
||||
// Load each object
|
||||
for (i = 0; i < OBJECT_ENTRY_COUNT; i++) {
|
||||
if (!check_object_entry(&entries[i]))
|
||||
for (int i = 0; i < OBJECT_ENTRY_COUNT; i++) {
|
||||
if (!check_object_entry(&entries[i])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get entry group index
|
||||
int entryGroupIndex = i;
|
||||
for (j = 0; j < countof(object_entry_group_counts); j++) {
|
||||
for (int j = 0; j < countof(object_entry_group_counts); j++) {
|
||||
if (entryGroupIndex < object_entry_group_counts[j])
|
||||
break;
|
||||
entryGroupIndex -= object_entry_group_counts[j];
|
||||
|
@ -561,18 +565,17 @@ int object_read_and_load_entries(SDL_RWops* rw)
|
|||
if (!object_load_chunk(entryGroupIndex, &entries[i], NULL)) {
|
||||
log_error("failed to load entry: %.8s", entries[i].name);
|
||||
memcpy((char*)RCT2_ADDRESS_COMMON_FORMAT_ARGS, &entries[i], sizeof(rct_object_entry));
|
||||
load_fail = 1;
|
||||
loadFailed = true;
|
||||
}
|
||||
}
|
||||
|
||||
free(entries);
|
||||
if (load_fail){
|
||||
if (loadFailed) {
|
||||
object_unload_all();
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
log_verbose("finished loading required objects");
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,580 @@
|
|||
#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/Exception.hpp"
|
||||
#include "../core/IStream.hpp"
|
||||
#include "../core/String.hpp"
|
||||
#include "S6Exporter.h"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include "../config.h"
|
||||
#include "../game.h"
|
||||
#include "../interface/viewport.h"
|
||||
#include "../interface/window.h"
|
||||
#include "../localisation/date.h"
|
||||
#include "../localisation/localisation.h"
|
||||
#include "../management/finance.h"
|
||||
#include "../management/marketing.h"
|
||||
#include "../management/news_item.h"
|
||||
#include "../management/research.h"
|
||||
#include "../object.h"
|
||||
#include "../openrct2.h"
|
||||
#include "../peep/staff.h"
|
||||
#include "../ride/ride.h"
|
||||
#include "../ride/ride_ratings.h"
|
||||
#include "../scenario.h"
|
||||
#include "../util/sawyercoding.h"
|
||||
#include "../world/climate.h"
|
||||
#include "../world/map_animation.h"
|
||||
#include "../world/park.h"
|
||||
}
|
||||
|
||||
S6Exporter::S6Exporter()
|
||||
{
|
||||
ExportObjects = false;
|
||||
RemoveTracklessRides = false;
|
||||
memset(&_s6, 0, sizeof(_s6));
|
||||
}
|
||||
|
||||
void S6Exporter::SaveGame(const utf8 * path)
|
||||
{
|
||||
SDL_RWops * rw = SDL_RWFromFile(path, "rb");
|
||||
if (rw == nullptr)
|
||||
{
|
||||
throw IOException("Unable to write to destination file.");
|
||||
}
|
||||
|
||||
SaveGame(rw);
|
||||
|
||||
SDL_RWclose(rw);
|
||||
}
|
||||
|
||||
void S6Exporter::SaveGame(SDL_RWops *rw)
|
||||
{
|
||||
Save(rw, false);
|
||||
}
|
||||
|
||||
void S6Exporter::SaveScenario(const utf8 * path)
|
||||
{
|
||||
SDL_RWops * rw = SDL_RWFromFile(path, "rb");
|
||||
if (rw == nullptr)
|
||||
{
|
||||
throw IOException("Unable to write to destination file.");
|
||||
}
|
||||
|
||||
SaveGame(rw);
|
||||
|
||||
SDL_RWclose(rw);
|
||||
}
|
||||
|
||||
void S6Exporter::SaveScenario(SDL_RWops *rw)
|
||||
{
|
||||
Save(rw, true);
|
||||
}
|
||||
|
||||
void S6Exporter::Save(SDL_RWops * rw, bool isScenario)
|
||||
{
|
||||
_s6.header.type = isScenario ? S6_TYPE_SCENARIO : S6_TYPE_SAVEDGAME;
|
||||
_s6.header.num_packed_objects = scenario_get_num_packed_objects_to_write();
|
||||
_s6.header.version = S6_RCT2_VERSION;
|
||||
_s6.header.magic_number = S6_MAGIC_NUMBER;
|
||||
|
||||
_s6.game_version_number = 201028;
|
||||
|
||||
uint8 * buffer = (uint8 *)malloc(0x600000);
|
||||
if (buffer == NULL)
|
||||
{
|
||||
log_error("Unable to allocate enough space for a write buffer.");
|
||||
throw Exception("Unable to allocate memory.");
|
||||
}
|
||||
|
||||
sawyercoding_chunk_header chunkHeader;
|
||||
int encodedLength;
|
||||
|
||||
// 0: Write header chunk
|
||||
chunkHeader.encoding = CHUNK_ENCODING_ROTATE;
|
||||
chunkHeader.length = sizeof(rct_s6_header);
|
||||
encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)&_s6.header, chunkHeader);
|
||||
SDL_RWwrite(rw, buffer, encodedLength, 1);
|
||||
|
||||
// 1: Write scenario info chunk
|
||||
if (_s6.header.type == S6_TYPE_SCENARIO)
|
||||
{
|
||||
chunkHeader.encoding = CHUNK_ENCODING_ROTATE;
|
||||
chunkHeader.length = sizeof(rct_s6_info);
|
||||
encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)&_s6.info, chunkHeader);
|
||||
SDL_RWwrite(rw, buffer, encodedLength, 1);
|
||||
}
|
||||
|
||||
// 2: Write packed objects
|
||||
if (_s6.header.num_packed_objects > 0)
|
||||
{
|
||||
if (!scenario_write_packed_objects(rw))
|
||||
{
|
||||
free(buffer);
|
||||
throw Exception("Unable to pack objects.");
|
||||
}
|
||||
}
|
||||
|
||||
// 3: Write available objects chunk
|
||||
chunkHeader.encoding = CHUNK_ENCODING_ROTATE;
|
||||
chunkHeader.length = 721 * sizeof(rct_object_entry);
|
||||
encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)_s6.objects, chunkHeader);
|
||||
SDL_RWwrite(rw, buffer, encodedLength, 1);
|
||||
|
||||
// 4: Misc fields (data, rand...) chunk
|
||||
chunkHeader.encoding = CHUNK_ENCODING_RLECOMPRESSED;
|
||||
chunkHeader.length = 16;
|
||||
encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)&_s6.elapsed_months, chunkHeader);
|
||||
SDL_RWwrite(rw, buffer, encodedLength, 1);
|
||||
|
||||
// 5: Map elements + sprites and other fields chunk
|
||||
chunkHeader.encoding = CHUNK_ENCODING_RLECOMPRESSED;
|
||||
chunkHeader.length = 0x180000;
|
||||
encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)_s6.map_elements, chunkHeader);
|
||||
SDL_RWwrite(rw, buffer, encodedLength, 1);
|
||||
|
||||
if (_s6.header.type == S6_TYPE_SCENARIO)
|
||||
{
|
||||
// 6:
|
||||
chunkHeader.encoding = CHUNK_ENCODING_RLECOMPRESSED;
|
||||
chunkHeader.length = 0x27104C;
|
||||
encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)&_s6.dword_010E63B8, chunkHeader);
|
||||
SDL_RWwrite(rw, buffer, encodedLength, 1);
|
||||
|
||||
// 7:
|
||||
chunkHeader.encoding = CHUNK_ENCODING_RLECOMPRESSED;
|
||||
chunkHeader.length = 4;
|
||||
encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)&_s6.guests_in_park, chunkHeader);
|
||||
SDL_RWwrite(rw, buffer, encodedLength, 1);
|
||||
|
||||
// 8:
|
||||
chunkHeader.encoding = CHUNK_ENCODING_RLECOMPRESSED;
|
||||
chunkHeader.length = 8;
|
||||
encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)&_s6.last_guests_in_park, chunkHeader);
|
||||
SDL_RWwrite(rw, buffer, encodedLength, 1);
|
||||
|
||||
// 9:
|
||||
chunkHeader.encoding = CHUNK_ENCODING_RLECOMPRESSED;
|
||||
chunkHeader.length = 2;
|
||||
encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)&_s6.park_rating, chunkHeader);
|
||||
SDL_RWwrite(rw, buffer, encodedLength, 1);
|
||||
|
||||
// 10:
|
||||
chunkHeader.encoding = CHUNK_ENCODING_RLECOMPRESSED;
|
||||
chunkHeader.length = 1082;
|
||||
encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)&_s6.active_research_types, chunkHeader);
|
||||
SDL_RWwrite(rw, buffer, encodedLength, 1);
|
||||
|
||||
// 11:
|
||||
chunkHeader.encoding = CHUNK_ENCODING_RLECOMPRESSED;
|
||||
chunkHeader.length = 16;
|
||||
encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)&_s6.current_expenditure, chunkHeader);
|
||||
SDL_RWwrite(rw, buffer, encodedLength, 1);
|
||||
|
||||
// 12:
|
||||
chunkHeader.encoding = CHUNK_ENCODING_RLECOMPRESSED;
|
||||
chunkHeader.length = 4;
|
||||
encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)&_s6.park_value, chunkHeader);
|
||||
SDL_RWwrite(rw, buffer, encodedLength, 1);
|
||||
|
||||
// 13:
|
||||
chunkHeader.encoding = CHUNK_ENCODING_RLECOMPRESSED;
|
||||
chunkHeader.length = 0x761E8;
|
||||
encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)&_s6.completed_company_value, chunkHeader);
|
||||
SDL_RWwrite(rw, buffer, encodedLength, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 6: Everything else...
|
||||
chunkHeader.encoding = CHUNK_ENCODING_RLECOMPRESSED;
|
||||
chunkHeader.length = 0x2E8570;
|
||||
encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)&_s6.dword_010E63B8, chunkHeader);
|
||||
SDL_RWwrite(rw, buffer, encodedLength, 1);
|
||||
}
|
||||
|
||||
free(buffer);
|
||||
|
||||
// Determine number of bytes written
|
||||
size_t fileSize = (size_t)SDL_RWtell(rw);
|
||||
SDL_RWseek(rw, 0, RW_SEEK_SET);
|
||||
|
||||
// Read all written bytes back into a single buffer
|
||||
buffer = (uint8 *)malloc(fileSize);
|
||||
SDL_RWread(rw, buffer, fileSize, 1);
|
||||
uint32 checksum = sawyercoding_calculate_checksum(buffer, fileSize);
|
||||
free(buffer);
|
||||
|
||||
// Append the checksum
|
||||
SDL_RWseek(rw, fileSize, RW_SEEK_SET);
|
||||
SDL_RWwrite(rw, &checksum, sizeof(uint32), 1);
|
||||
}
|
||||
|
||||
void S6Exporter::Export()
|
||||
{
|
||||
_s6.info = *(RCT2_ADDRESS(0x0141F570, rct_s6_info));
|
||||
|
||||
for (int i = 0; i < 721; i++)
|
||||
{
|
||||
rct_object_entry_extended *entry = &(RCT2_ADDRESS(0x00F3F03C, rct_object_entry_extended)[i]);
|
||||
|
||||
if (gObjectList[i] == (void *)0xFFFFFFFF)
|
||||
{
|
||||
memset(&_s6.objects[i], 0xFF, sizeof(rct_object_entry));
|
||||
}
|
||||
else
|
||||
{
|
||||
_s6.objects[i] = *((rct_object_entry*)entry);
|
||||
}
|
||||
}
|
||||
|
||||
_s6.elapsed_months = gDateMonthsElapsed;
|
||||
_s6.current_day = gDateMonthTicks;
|
||||
_s6.scenario_ticks = RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TICKS, uint32);
|
||||
_s6.scenario_srand_0 = gScenarioSrand0;
|
||||
_s6.scenario_srand_1 = gScenarioSrand1;
|
||||
|
||||
memcpy(_s6.map_elements, gMapElements, sizeof(_s6.map_elements));
|
||||
|
||||
_s6.dword_010E63B8 = RCT2_GLOBAL(0x0010E63B8, uint32);
|
||||
memcpy(_s6.sprites, g_sprite_list, sizeof(_s6.sprites));
|
||||
|
||||
_s6.sprites_next_index = RCT2_GLOBAL(RCT2_ADDRESS_SPRITES_NEXT_INDEX, uint16);
|
||||
_s6.sprites_start_vehicle = RCT2_GLOBAL(RCT2_ADDRESS_SPRITES_START_VEHICLE, uint16);
|
||||
_s6.sprites_start_peep = RCT2_GLOBAL(RCT2_ADDRESS_SPRITES_START_PEEP, uint16);
|
||||
_s6.sprites_start_textfx = RCT2_GLOBAL(RCT2_ADDRESS_SPRITES_START_MISC, uint16);
|
||||
_s6.sprites_start_litter = RCT2_GLOBAL(RCT2_ADDRESS_SPRITES_START_LITTER, uint16);
|
||||
// pad_013573C6
|
||||
_s6.word_013573C8 = RCT2_GLOBAL(0x13573C8, uint16);
|
||||
_s6.sprites_next_index = RCT2_GLOBAL(RCT2_ADDRESS_SPRITES_COUNT_VEHICLE, uint16);
|
||||
_s6.sprites_count_peep = RCT2_GLOBAL(RCT2_ADDRESS_SPRITES_COUNT_PEEP, uint16);
|
||||
_s6.sprites_count_misc = RCT2_GLOBAL(RCT2_ADDRESS_SPRITES_COUNT_MISC, uint16);
|
||||
_s6.sprites_count_litter = RCT2_GLOBAL(RCT2_ADDRESS_SPRITES_COUNT_LITTER, uint16);
|
||||
// pad_013573D2
|
||||
_s6.park_name = gParkName;
|
||||
// pad_013573D6
|
||||
_s6.park_name_args = gParkNameArgs;
|
||||
_s6.initial_cash = gInitialCash;
|
||||
_s6.current_loan = gBankLoan;
|
||||
_s6.park_flags = gParkFlags;
|
||||
_s6.park_entrance_fee = gParkEntranceFee;
|
||||
// rct1_park_entrance_x
|
||||
// rct1_park_entrance_y
|
||||
// pad_013573EE
|
||||
// rct1_park_entrance_z
|
||||
memcpy(_s6.peep_spawns, gPeepSpawns, sizeof(_s6.peep_spawns));
|
||||
_s6.guest_count_change_modifier = gGuestChangeModifier;
|
||||
_s6.current_research_level = gResearchFundingLevel;
|
||||
// pad_01357400
|
||||
memcpy(_s6.ride_types_researched, RCT2_ADDRESS(0x01357404, uint32), sizeof(_s6.ride_types_researched));
|
||||
memcpy(_s6.ride_entries_researched, RCT2_ADDRESS(0x01357424, uint32), sizeof(_s6.ride_entries_researched));
|
||||
memcpy(_s6.dword_01357444, RCT2_ADDRESS(0x01357444, uint32), sizeof(_s6.dword_01357444));
|
||||
memcpy(_s6.dword_01357644, RCT2_ADDRESS(0x01357644, uint32), sizeof(_s6.dword_01357644));
|
||||
|
||||
_s6.guests_in_park = gNumGuestsInPark;
|
||||
_s6.guests_heading_for_park = gNumGuestsHeadingForPark;
|
||||
|
||||
memcpy(_s6.expenditure_table, RCT2_ADDRESS(RCT2_ADDRESS_EXPENDITURE_TABLE, money32), sizeof(_s6.expenditure_table));
|
||||
memcpy(_s6.dword_01357880, RCT2_ADDRESS(0x01357880, uint32), sizeof(_s6.dword_01357880));
|
||||
_s6.monthly_ride_income = RCT2_GLOBAL(RCT2_ADDRESS_MONTHLY_RIDE_INCOME, money32);
|
||||
_s6.dword_01357898 = RCT2_GLOBAL(0x01357898, money32);
|
||||
_s6.dword_0135789C = RCT2_GLOBAL(0x0135789C, money32);
|
||||
_s6.dword_013578A0 = RCT2_GLOBAL(0x013578A0, money32);
|
||||
memcpy(_s6.dword_013578A4, RCT2_ADDRESS(0x013578A4, money32), sizeof(_s6.dword_013578A4));
|
||||
|
||||
_s6.last_guests_in_park = RCT2_GLOBAL(RCT2_ADDRESS_LAST_GUESTS_IN_PARK, uint16);
|
||||
// pad_01357BCA
|
||||
_s6.handyman_colour = gStaffHandymanColour;
|
||||
_s6.mechanic_colour = gStaffMechanicColour;
|
||||
_s6.security_colour = gStaffSecurityColour;
|
||||
|
||||
memcpy(_s6.dword_01357BD0, RCT2_ADDRESS(0x01357BD0, uint32), sizeof(_s6.dword_01357BD0));
|
||||
|
||||
_s6.park_rating = gParkRating;
|
||||
|
||||
memcpy(_s6.park_rating_history, gParkRatingHistory, sizeof(_s6.park_rating_history));
|
||||
memcpy(_s6.guests_in_park_history, gGuestsInParkHistory, sizeof(_s6.guests_in_park_history));
|
||||
|
||||
_s6.active_research_types = gResearchPriorities;
|
||||
_s6.research_progress_stage = gResearchProgressStage;
|
||||
_s6.last_researched_item_subject = RCT2_GLOBAL(RCT2_ADDRESS_LAST_RESEARCHED_ITEM_SUBJECT, uint32);
|
||||
// pad_01357CF8
|
||||
_s6.next_research_item = gResearchNextItem;
|
||||
_s6.research_progress = gResearchProgress;
|
||||
_s6.next_research_category = gResearchNextCategory;
|
||||
_s6.next_research_expected_day = gResearchExpectedDay;
|
||||
_s6.next_research_expected_month = gResearchExpectedMonth;
|
||||
_s6.guest_initial_happiness = gGuestInitialHappiness;
|
||||
_s6.park_size = gParkSize;
|
||||
_s6.guest_generation_probability = _guestGenerationProbability;
|
||||
_s6.total_ride_value = gTotalRideValue;
|
||||
_s6.maximum_loan = gMaxBankLoan;
|
||||
_s6.guest_initial_cash = gGuestInitialCash;
|
||||
_s6.guest_initial_hunger = gGuestInitialHunger;
|
||||
_s6.guest_initial_thirst = gGuestInitialThirst;
|
||||
_s6.objective_type = gScenarioObjectiveType;
|
||||
_s6.objective_year = gScenarioObjectiveYear;
|
||||
// pad_013580FA
|
||||
_s6.objective_currency = gScenarioObjectiveCurrency;
|
||||
_s6.objective_guests = gScenarioObjectiveNumGuests;
|
||||
memcpy(_s6.campaign_weeks_left, gMarketingCampaignDaysLeft, sizeof(_s6.campaign_weeks_left));
|
||||
memcpy(_s6.campaign_ride_index, gMarketingCampaignRideIndex, sizeof(_s6.campaign_ride_index));
|
||||
|
||||
memcpy(_s6.balance_history, gCashHistory, sizeof(_s6.balance_history));
|
||||
|
||||
_s6.current_expenditure = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_EXPENDITURE, money32);
|
||||
_s6.current_profit = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_PROFIT, money32);
|
||||
_s6.dword_01358334 = RCT2_GLOBAL(0x01358334, uint32);
|
||||
_s6.word_01358338 = RCT2_GLOBAL(0x01358338, uint16);
|
||||
// pad_0135833A
|
||||
|
||||
memcpy(_s6.weekly_profit_history, gWeeklyProfitHistory, sizeof(_s6.weekly_profit_history));
|
||||
|
||||
_s6.park_value = gParkValue;
|
||||
|
||||
memcpy(_s6.park_value_history, gParkValueHistory, sizeof(_s6.park_value_history));
|
||||
|
||||
_s6.completed_company_value = gScenarioCompletedCompanyValue;
|
||||
_s6.total_admissions = RCT2_GLOBAL(RCT2_ADDRESS_TOTAL_ADMISSIONS, money32);
|
||||
_s6.income_from_admissions = RCT2_GLOBAL(RCT2_ADDRESS_INCOME_FROM_ADMISSIONS, money32);
|
||||
_s6.company_value = gCompanyValue;
|
||||
memcpy(_s6.byte_01358750, RCT2_ADDRESS(0x01358750, uint8), sizeof(_s6.byte_01358750));
|
||||
memcpy(_s6.awards, gCurrentAwards, sizeof(_s6.awards));
|
||||
_s6.land_price = gLandPrice;
|
||||
_s6.construction_rights_price = gConstructionRightsPrice;
|
||||
_s6.word_01358774 = RCT2_GLOBAL(0x01358774, uint16);
|
||||
// pad_01358776
|
||||
memcpy(_s6.dword_01358778, RCT2_ADDRESS(0x01358778, uint32), sizeof(_s6.dword_01358778));
|
||||
// _s6.game_version_number
|
||||
_s6.dword_013587C0 = RCT2_GLOBAL(0x013587C0, uint32);
|
||||
_s6.loan_hash = RCT2_GLOBAL(RCT2_ADDRESS_LOAN_HASH, uint32);
|
||||
_s6.ride_count = RCT2_GLOBAL(RCT2_ADDRESS_RIDE_COUNT, uint16);
|
||||
// pad_013587CA
|
||||
_s6.dword_013587D0 = RCT2_GLOBAL(0x013587D0, uint32);
|
||||
// pad_013587D4
|
||||
memcpy(_s6.scenario_completed_name, gScenarioCompletedBy, sizeof(_s6.scenario_completed_name));
|
||||
_s6.cash = gCashEncrypted;
|
||||
// pad_013587FC
|
||||
_s6.word_0135882E = RCT2_GLOBAL(0x0135882E, uint16);
|
||||
_s6.map_size_units = gMapSizeUnits;
|
||||
_s6.map_size_minus_2 = gMapSizeMinus2;
|
||||
_s6.map_size = gMapSize;
|
||||
_s6.map_max_xy = gMapSizeMaxXY;
|
||||
_s6.same_price_throughout = RCT2_GLOBAL(RCT2_ADDRESS_SAME_PRICE_THROUGHOUT, uint32);
|
||||
_s6.suggested_max_guests = _suggestedGuestMaximum;
|
||||
_s6.park_rating_warning_days = gScenarioParkRatingWarningDays;
|
||||
_s6.last_entrance_style = RCT2_GLOBAL(RCT2_ADDRESS_LAST_ENTRANCE_STYLE, uint8);
|
||||
// rct1_water_colour
|
||||
// pad_01358842
|
||||
memcpy(_s6.research_items, gResearchItems, sizeof(_s6.research_items));
|
||||
_s6.word_01359208 = RCT2_GLOBAL(0x01359208, uint16);
|
||||
memcpy(_s6.scenario_name, gScenarioName, sizeof(_s6.scenario_name));
|
||||
memcpy(_s6.scenario_description, gScenarioDetails, sizeof(_s6.scenario_description));
|
||||
_s6.current_interest_rate = gBankLoanInterestRate;
|
||||
// pad_0135934B
|
||||
_s6.same_price_throughout_extended = RCT2_GLOBAL(RCT2_ADDRESS_SAME_PRICE_THROUGHOUT_EXTENDED, uint32);
|
||||
memcpy(_s6.park_entrance_x, gParkEntranceX, sizeof(_s6.park_entrance_x));
|
||||
memcpy(_s6.park_entrance_y, gParkEntranceY, sizeof(_s6.park_entrance_y));
|
||||
memcpy(_s6.park_entrance_z, gParkEntranceZ, sizeof(_s6.park_entrance_z));
|
||||
memcpy(_s6.park_entrance_direction, gParkEntranceDirection, sizeof(_s6.park_entrance_direction));
|
||||
memcpy(_s6.scenario_filename, RCT2_ADDRESS(0x0135936C, char), sizeof(_s6.scenario_filename));
|
||||
memcpy(_s6.saved_expansion_pack_names, RCT2_ADDRESS(0x0135946C, uint8), sizeof(_s6.saved_expansion_pack_names));
|
||||
memcpy(_s6.banners, gBanners, sizeof(_s6.banners));
|
||||
memcpy(_s6.custom_strings, gUserStrings, sizeof(_s6.custom_strings));
|
||||
_s6.game_ticks_1 = RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TICKS, uint32);
|
||||
memcpy(_s6.rides, RCT2_ADDRESS(RCT2_ADDRESS_RIDE_LIST, rct_ride*), sizeof(_s6.rides));
|
||||
_s6.saved_age = RCT2_GLOBAL(RCT2_ADDRESS_SAVED_AGE, uint16);
|
||||
_s6.saved_view_x = RCT2_GLOBAL(RCT2_ADDRESS_SAVED_VIEW_X, uint16);
|
||||
_s6.saved_view_y = RCT2_GLOBAL(RCT2_ADDRESS_SAVED_VIEW_Y, uint16);
|
||||
_s6.saved_view_zoom_and_rotation = RCT2_GLOBAL(RCT2_ADDRESS_SAVED_VIEW_ZOOM_AND_ROTATION, uint16);
|
||||
memcpy(_s6.map_animations, RCT2_ADDRESS(gAnimatedObjects, rct_map_animation), sizeof(_s6.map_animations));
|
||||
// rct1_map_animations
|
||||
_s6.num_map_animations = RCT2_GLOBAL(0x0138B580, uint16);
|
||||
// pad_0138B582
|
||||
|
||||
_s6.ride_ratings_proximity_x = _rideRatingsProximityX;
|
||||
_s6.ride_ratings_proximity_y = _rideRatingsProximityY;
|
||||
_s6.ride_ratings_proximity_z = _rideRatingsProximityZ;
|
||||
_s6.ride_ratings_proximity_start_x = _rideRatingsProximityStartX;
|
||||
_s6.ride_ratings_proximity_start_y = _rideRatingsProximityStartY;
|
||||
_s6.ride_ratings_proximity_start_z = _rideRatingsProximityStartZ;
|
||||
_s6.ride_ratings_current_ride = _rideRatingsCurrentRide;
|
||||
_s6.ride_ratings_state = _rideRatingsState;
|
||||
_s6.ride_ratings_proximity_track_type = _rideRatingsProximityTrackType;
|
||||
_s6.ride_ratings_proximity_base_height = _rideRatingsProximityBaseHeight;
|
||||
_s6.ride_ratings_proximity_total = _rideRatingsProximityTotal;
|
||||
memcpy(_s6.ride_ratings_proximity_scores, _proximityScores, sizeof(_s6.ride_ratings_proximity_scores));
|
||||
_s6.ride_ratings_num_brakes = _rideRatingsNumBrakes;
|
||||
_s6.ride_ratings_num_reversers = _rideRatingsNumReversers;
|
||||
_s6.word_0138B5CE = RCT2_GLOBAL(0x00138B5CE, uint16);
|
||||
memcpy(_s6.ride_measurements, RCT2_ADDRESS(RCT2_ADDRESS_RIDE_MEASUREMENTS, rct_ride_measurement), sizeof(_s6.ride_measurements));
|
||||
_s6.next_guest_index = RCT2_GLOBAL(0x013B0E6C, uint32);
|
||||
_s6.grass_and_scenery_tilepos = gGrassSceneryTileLoopPosition;
|
||||
memcpy(_s6.patrol_areas, gStaffPatrolAreas, sizeof(_s6.patrol_areas));
|
||||
memcpy(_s6.staff_modes, gStaffModes, sizeof(_s6.staff_modes));
|
||||
// unk_13CA73E
|
||||
// pad_13CA73F
|
||||
_s6.byte_13CA740 = RCT2_GLOBAL(0x013CA740, uint8);
|
||||
_s6.climate = gClimate;
|
||||
// pad_13CA741;
|
||||
memcpy(_s6.byte_13CA742, RCT2_ADDRESS(0x013CA742, uint8), sizeof(_s6.byte_13CA742));
|
||||
// pad_013CA747
|
||||
_s6.climate_update_timer = gClimateUpdateTimer;
|
||||
_s6.current_weather = gClimateCurrentWeather;
|
||||
_s6.next_weather = gClimateNextWeather;
|
||||
_s6.temperature = gClimateNextTemperature;
|
||||
_s6.current_weather_effect = gClimateCurrentWeatherEffect;
|
||||
_s6.next_weather_effect = gClimateNextWeatherEffect;
|
||||
_s6.current_weather_gloom = gClimateCurrentWeatherGloom;
|
||||
_s6.next_weather_gloom = gClimateNextWeatherGloom;
|
||||
_s6.current_rain_level = gClimateCurrentRainLevel;
|
||||
_s6.next_rain_level = gClimateNextRainLevel;
|
||||
memcpy(_s6.news_items, gNewsItems, sizeof(_s6.news_items));
|
||||
// pad_13CE730
|
||||
// rct1_scenario_flags
|
||||
_s6.wide_path_tile_loop_x = gWidePathTileLoopX;
|
||||
_s6.wide_path_tile_loop_y = gWidePathTileLoopY;
|
||||
// pad_13CE778
|
||||
|
||||
String::Set(_s6.scenario_filename, sizeof(_s6.scenario_filename), _scenarioFileName);
|
||||
|
||||
if (RemoveTracklessRides)
|
||||
{
|
||||
scenario_remove_trackless_rides(&_s6);
|
||||
}
|
||||
|
||||
scenario_fix_ghosts(&_s6);
|
||||
game_convert_strings_to_rct2(&_s6);
|
||||
}
|
||||
|
||||
extern "C"
|
||||
{
|
||||
enum {
|
||||
S6_SAVE_FLAG_EXPORT = 1 << 0,
|
||||
S6_SAVE_FLAG_SCENARIO = 1 << 1,
|
||||
S6_SAVE_FLAG_AUTOMATIC = 1 << 31,
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* rct2: 0x006754F5
|
||||
* @param flags bit 0: pack objects, 1: save as scenario
|
||||
*/
|
||||
int scenario_save(SDL_RWops* rw, int flags)
|
||||
{
|
||||
if (flags & S6_SAVE_FLAG_SCENARIO)
|
||||
{
|
||||
log_verbose("saving scenario");
|
||||
}
|
||||
else
|
||||
{
|
||||
log_verbose("saving game");
|
||||
}
|
||||
|
||||
if (!(flags & S6_SAVE_FLAG_AUTOMATIC))
|
||||
{
|
||||
window_close_construction_windows();
|
||||
}
|
||||
|
||||
map_reorganise_elements();
|
||||
reset_0x69EBE4();
|
||||
sprite_clear_all_unused();
|
||||
|
||||
viewport_set_saved_view();
|
||||
|
||||
bool result = false;
|
||||
auto s6exporter = new S6Exporter();
|
||||
try
|
||||
{
|
||||
s6exporter->ExportObjects = (flags & S6_SAVE_FLAG_EXPORT);
|
||||
s6exporter->RemoveTracklessRides = true;
|
||||
s6exporter->Export();
|
||||
if (flags & S6_SAVE_FLAG_SCENARIO)
|
||||
{
|
||||
s6exporter->SaveScenario(rw);
|
||||
}
|
||||
else
|
||||
{
|
||||
s6exporter->SaveGame(rw);
|
||||
}
|
||||
result = true;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
delete s6exporter;
|
||||
|
||||
reset_loaded_objects();
|
||||
gfx_invalidate_screen();
|
||||
|
||||
if (result && !(flags & S6_SAVE_FLAG_AUTOMATIC))
|
||||
{
|
||||
gScreenAge = 0;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Save game state without modifying any of the state for multiplayer
|
||||
int scenario_save_network(SDL_RWops * rw)
|
||||
{
|
||||
viewport_set_saved_view();
|
||||
|
||||
bool result = false;
|
||||
auto s6exporter = new S6Exporter();
|
||||
try
|
||||
{
|
||||
s6exporter->Export();
|
||||
s6exporter->SaveGame(rw);
|
||||
result = true;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
delete s6exporter;
|
||||
|
||||
if (!result)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
reset_loaded_objects();
|
||||
|
||||
// Write other data not in normal save files
|
||||
SDL_WriteLE32(rw, gGamePaused);
|
||||
SDL_WriteLE32(rw, _guestGenerationProbability);
|
||||
SDL_WriteLE32(rw, _suggestedGuestMaximum);
|
||||
SDL_WriteU8(rw, gCheatsSandboxMode);
|
||||
SDL_WriteU8(rw, gCheatsDisableClearanceChecks);
|
||||
SDL_WriteU8(rw, gCheatsDisableSupportLimits);
|
||||
SDL_WriteU8(rw, gCheatsDisableTrainLengthLimit);
|
||||
SDL_WriteU8(rw, gCheatsShowAllOperatingModes);
|
||||
SDL_WriteU8(rw, gCheatsShowVehiclesFromOtherTrackTypes);
|
||||
SDL_WriteU8(rw, gCheatsFastLiftHill);
|
||||
SDL_WriteU8(rw, gCheatsDisableBrakesFailure);
|
||||
SDL_WriteU8(rw, gCheatsDisableAllBreakdowns);
|
||||
SDL_WriteU8(rw, gCheatsUnlockAllPrices);
|
||||
SDL_WriteU8(rw, gCheatsBuildInPauseMode);
|
||||
SDL_WriteU8(rw, gCheatsIgnoreRideIntensity);
|
||||
SDL_WriteU8(rw, gCheatsDisableVandalism);
|
||||
SDL_WriteU8(rw, gCheatsDisableLittering);
|
||||
SDL_WriteU8(rw, gCheatsNeverendingMarketing);
|
||||
SDL_WriteU8(rw, gCheatsFreezeClimate);
|
||||
|
||||
gfx_invalidate_screen();
|
||||
return 1;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
#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 "../common.h"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include "../scenario.h"
|
||||
}
|
||||
|
||||
/**
|
||||
* Class to export RollerCoaster Tycoon 2 scenarios (*.SC6) and saved games (*.SV6).
|
||||
*/
|
||||
class S6Exporter
|
||||
{
|
||||
public:
|
||||
bool ExportObjects;
|
||||
bool RemoveTracklessRides;
|
||||
|
||||
S6Exporter();
|
||||
|
||||
void SaveGame(const utf8 * path);
|
||||
void SaveGame(SDL_RWops *rw);
|
||||
void SaveScenario(const utf8 * path);
|
||||
void SaveScenario(SDL_RWops *rw);
|
||||
void Export();
|
||||
|
||||
private:
|
||||
rct_s6_data _s6;
|
||||
|
||||
void Save(SDL_RWops *rw, bool isScenario);
|
||||
};
|
|
@ -0,0 +1,534 @@
|
|||
#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/Exception.hpp"
|
||||
#include "../core/IStream.hpp"
|
||||
#include "S6Importer.h"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include "../config.h"
|
||||
#include "../game.h"
|
||||
#include "../localisation/date.h"
|
||||
#include "../localisation/localisation.h"
|
||||
#include "../management/finance.h"
|
||||
#include "../management/marketing.h"
|
||||
#include "../management/news_item.h"
|
||||
#include "../management/research.h"
|
||||
#include "../openrct2.h"
|
||||
#include "../peep/staff.h"
|
||||
#include "../ride/ride.h"
|
||||
#include "../ride/ride_ratings.h"
|
||||
#include "../scenario.h"
|
||||
#include "../util/sawyercoding.h"
|
||||
#include "../world/climate.h"
|
||||
#include "../world/map_animation.h"
|
||||
#include "../world/park.h"
|
||||
}
|
||||
|
||||
class ObjectLoadException : public Exception
|
||||
{
|
||||
public:
|
||||
ObjectLoadException() : Exception("Unable to load objects.") { }
|
||||
ObjectLoadException(const char * message) : Exception(message) { }
|
||||
};
|
||||
|
||||
S6Importer::S6Importer()
|
||||
{
|
||||
FixIssues = false;
|
||||
memset(&_s6, 0, sizeof(_s6));
|
||||
}
|
||||
|
||||
void S6Importer::LoadSavedGame(const utf8 * path)
|
||||
{
|
||||
SDL_RWops * rw = SDL_RWFromFile(path, "rb");
|
||||
if (rw == nullptr)
|
||||
{
|
||||
throw IOException("Unable to open SV6.");
|
||||
}
|
||||
|
||||
if (!sawyercoding_validate_checksum(rw))
|
||||
{
|
||||
gErrorType = ERROR_TYPE_FILE_LOAD;
|
||||
gGameCommandErrorTitle = STR_FILE_CONTAINS_INVALID_DATA;
|
||||
|
||||
log_error("failed to load saved game, invalid checksum");
|
||||
throw IOException("Invalid SV6 checksum.");
|
||||
}
|
||||
|
||||
LoadSavedGame(rw);
|
||||
|
||||
SDL_RWclose(rw);
|
||||
|
||||
_s6Path = path;
|
||||
}
|
||||
|
||||
void S6Importer::LoadScenario(const utf8 * path)
|
||||
{
|
||||
SDL_RWops * rw = SDL_RWFromFile(path, "rb");
|
||||
if (rw == nullptr)
|
||||
{
|
||||
throw IOException("Unable to open SV6.");
|
||||
}
|
||||
|
||||
if (!gConfigGeneral.allow_loading_with_incorrect_checksum && !sawyercoding_validate_checksum(rw))
|
||||
{
|
||||
SDL_RWclose(rw);
|
||||
|
||||
gErrorType = ERROR_TYPE_FILE_LOAD;
|
||||
gErrorStringId = STR_FILE_CONTAINS_INVALID_DATA;
|
||||
|
||||
log_error("failed to load scenario, invalid checksum");
|
||||
throw IOException("Invalid SC6 checksum.");
|
||||
}
|
||||
|
||||
LoadScenario(rw);
|
||||
|
||||
SDL_RWclose(rw);
|
||||
|
||||
_s6Path = path;
|
||||
}
|
||||
|
||||
void S6Importer::LoadSavedGame(SDL_RWops *rw)
|
||||
{
|
||||
auto meh = SDL_RWtell(rw);
|
||||
|
||||
sawyercoding_read_chunk(rw, (uint8*)&_s6.header);
|
||||
if (_s6.header.type != S6_TYPE_SAVEDGAME)
|
||||
{
|
||||
throw Exception("Data is not a saved game.");
|
||||
}
|
||||
|
||||
// Read packed objects
|
||||
// TODO try to contain this more and not store objects until later
|
||||
if (_s6.header.num_packed_objects > 0) {
|
||||
int j = 0;
|
||||
for (uint16 i = 0; i < _s6.header.num_packed_objects; i++)
|
||||
{
|
||||
j += object_load_packed(rw);
|
||||
}
|
||||
if (j > 0)
|
||||
{
|
||||
object_list_load();
|
||||
}
|
||||
}
|
||||
|
||||
sawyercoding_read_chunk(rw, (uint8*)&_s6.objects);
|
||||
sawyercoding_read_chunk(rw, (uint8*)&_s6.elapsed_months);
|
||||
sawyercoding_read_chunk(rw, (uint8*)&_s6.map_elements);
|
||||
sawyercoding_read_chunk(rw, (uint8*)&_s6.dword_010E63B8);
|
||||
}
|
||||
|
||||
void S6Importer::LoadScenario(SDL_RWops *rw)
|
||||
{
|
||||
sawyercoding_read_chunk(rw, (uint8*)&_s6.header);
|
||||
if (_s6.header.type != S6_TYPE_SCENARIO)
|
||||
{
|
||||
throw Exception("Data is not a scenario.");
|
||||
}
|
||||
|
||||
sawyercoding_read_chunk(rw, (uint8*)&_s6.info);
|
||||
|
||||
// Read packed objects
|
||||
// TODO try to contain this more and not store objects until later
|
||||
if (_s6.header.num_packed_objects > 0) {
|
||||
int j = 0;
|
||||
for (uint16 i = 0; i < _s6.header.num_packed_objects; i++)
|
||||
{
|
||||
j += object_load_packed(rw);
|
||||
}
|
||||
if (j > 0)
|
||||
{
|
||||
object_list_load();
|
||||
}
|
||||
}
|
||||
|
||||
sawyercoding_read_chunk(rw, (uint8*)&_s6.objects);
|
||||
sawyercoding_read_chunk(rw, (uint8*)&_s6.elapsed_months);
|
||||
sawyercoding_read_chunk(rw, (uint8*)&_s6.map_elements);
|
||||
sawyercoding_read_chunk(rw, (uint8*)&_s6.dword_010E63B8);
|
||||
sawyercoding_read_chunk(rw, (uint8*)&_s6.guests_in_park);
|
||||
sawyercoding_read_chunk(rw, (uint8*)&_s6.last_guests_in_park);
|
||||
sawyercoding_read_chunk(rw, (uint8*)&_s6.park_rating);
|
||||
sawyercoding_read_chunk(rw, (uint8*)&_s6.active_research_types);
|
||||
sawyercoding_read_chunk(rw, (uint8*)&_s6.current_expenditure);
|
||||
sawyercoding_read_chunk(rw, (uint8*)&_s6.park_value);
|
||||
sawyercoding_read_chunk(rw, (uint8*)&_s6.completed_company_value);
|
||||
}
|
||||
|
||||
void S6Importer::Import()
|
||||
{
|
||||
RCT2_GLOBAL(0x009E34E4, rct_s6_header) = _s6.header;
|
||||
|
||||
gDateMonthsElapsed = _s6.elapsed_months;
|
||||
gDateMonthTicks = _s6.current_day;
|
||||
RCT2_GLOBAL(RCT2_ADDRESS_SCENARIO_TICKS, uint32) = _s6.scenario_ticks;
|
||||
gScenarioSrand0 = _s6.scenario_srand_0;
|
||||
gScenarioSrand1 = _s6.scenario_srand_1;
|
||||
|
||||
memcpy(gMapElements, _s6.map_elements, sizeof(_s6.map_elements));
|
||||
|
||||
RCT2_GLOBAL(0x0010E63B8, uint32) = _s6.dword_010E63B8;
|
||||
memcpy(g_sprite_list, _s6.sprites, sizeof(_s6.sprites));
|
||||
|
||||
RCT2_GLOBAL(RCT2_ADDRESS_SPRITES_NEXT_INDEX, uint16) = _s6.sprites_next_index;
|
||||
RCT2_GLOBAL(RCT2_ADDRESS_SPRITES_START_VEHICLE, uint16) = _s6.sprites_start_vehicle;
|
||||
RCT2_GLOBAL(RCT2_ADDRESS_SPRITES_START_PEEP, uint16) = _s6.sprites_start_peep;
|
||||
RCT2_GLOBAL(RCT2_ADDRESS_SPRITES_START_MISC, uint16) = _s6.sprites_start_textfx;
|
||||
RCT2_GLOBAL(RCT2_ADDRESS_SPRITES_START_LITTER, uint16) = _s6.sprites_start_litter;
|
||||
// pad_013573C6
|
||||
RCT2_GLOBAL(0x13573C8, uint16) = _s6.word_013573C8;
|
||||
RCT2_GLOBAL(RCT2_ADDRESS_SPRITES_COUNT_VEHICLE, uint16) = _s6.sprites_next_index;
|
||||
RCT2_GLOBAL(RCT2_ADDRESS_SPRITES_COUNT_PEEP, uint16) = _s6.sprites_count_peep;
|
||||
RCT2_GLOBAL(RCT2_ADDRESS_SPRITES_COUNT_MISC, uint16) = _s6.sprites_count_misc;
|
||||
RCT2_GLOBAL(RCT2_ADDRESS_SPRITES_COUNT_LITTER, uint16) = _s6.sprites_count_litter;
|
||||
// pad_013573D2
|
||||
gParkName = _s6.park_name;
|
||||
// pad_013573D6
|
||||
gParkNameArgs = _s6.park_name_args;
|
||||
gInitialCash = _s6.initial_cash;
|
||||
gBankLoan = _s6.current_loan;
|
||||
gParkFlags = _s6.park_flags;
|
||||
gParkEntranceFee = _s6.park_entrance_fee;
|
||||
// rct1_park_entrance_x
|
||||
// rct1_park_entrance_y
|
||||
// pad_013573EE
|
||||
// rct1_park_entrance_z
|
||||
memcpy(gPeepSpawns, _s6.peep_spawns, sizeof(_s6.peep_spawns));
|
||||
gGuestChangeModifier = _s6.guest_count_change_modifier;
|
||||
gResearchFundingLevel = _s6.current_research_level;
|
||||
// pad_01357400
|
||||
memcpy(RCT2_ADDRESS(0x01357404, uint32), _s6.ride_types_researched, sizeof(_s6.ride_types_researched));
|
||||
memcpy(RCT2_ADDRESS(0x01357424, uint32), _s6.ride_entries_researched, sizeof(_s6.ride_entries_researched));
|
||||
memcpy(RCT2_ADDRESS(0x01357444, uint32), _s6.dword_01357444, sizeof(_s6.dword_01357444));
|
||||
memcpy(RCT2_ADDRESS(0x01357644, uint32), _s6.dword_01357644, sizeof(_s6.dword_01357644));
|
||||
|
||||
gNumGuestsInPark = _s6.guests_in_park;
|
||||
gNumGuestsHeadingForPark = _s6.guests_heading_for_park;
|
||||
|
||||
memcpy(RCT2_ADDRESS(RCT2_ADDRESS_EXPENDITURE_TABLE, money32), _s6.expenditure_table, sizeof(_s6.expenditure_table));
|
||||
memcpy(RCT2_ADDRESS(0x01357880, uint32), _s6.dword_01357880, sizeof(_s6.dword_01357880));
|
||||
RCT2_GLOBAL(RCT2_ADDRESS_MONTHLY_RIDE_INCOME, money32) = _s6.monthly_ride_income;
|
||||
RCT2_GLOBAL(0x01357898, money32) = _s6.dword_01357898;
|
||||
RCT2_GLOBAL(0x0135789C, money32) = _s6.dword_0135789C;
|
||||
RCT2_GLOBAL(0x013578A0, money32) = _s6.dword_013578A0;
|
||||
memcpy(RCT2_ADDRESS(0x013578A4, money32), _s6.dword_013578A4, sizeof(_s6.dword_013578A4));
|
||||
|
||||
RCT2_GLOBAL(RCT2_ADDRESS_LAST_GUESTS_IN_PARK, uint16) = _s6.last_guests_in_park;
|
||||
// pad_01357BCA
|
||||
gStaffHandymanColour = _s6.handyman_colour;
|
||||
gStaffMechanicColour = _s6.mechanic_colour;
|
||||
gStaffSecurityColour = _s6.security_colour;
|
||||
|
||||
memcpy(RCT2_ADDRESS(0x01357BD0, uint32), _s6.dword_01357BD0, sizeof(_s6.dword_01357BD0));
|
||||
|
||||
gParkRating = _s6.park_rating;
|
||||
|
||||
memcpy(gParkRatingHistory, _s6.park_rating_history, sizeof(_s6.park_rating_history));
|
||||
memcpy(gGuestsInParkHistory, _s6.guests_in_park_history, sizeof(_s6.guests_in_park_history));
|
||||
|
||||
gResearchPriorities = _s6.active_research_types;
|
||||
gResearchProgressStage = _s6.research_progress_stage;
|
||||
RCT2_GLOBAL(RCT2_ADDRESS_LAST_RESEARCHED_ITEM_SUBJECT, uint32) = _s6.last_researched_item_subject;
|
||||
// pad_01357CF8
|
||||
gResearchNextItem = _s6.next_research_item;
|
||||
gResearchProgress = _s6.research_progress;
|
||||
gResearchNextCategory = _s6.next_research_category;
|
||||
gResearchExpectedDay = _s6.next_research_expected_day;
|
||||
gResearchExpectedMonth = _s6.next_research_expected_month;
|
||||
gGuestInitialHappiness = _s6.guest_initial_happiness;
|
||||
gParkSize = _s6.park_size;
|
||||
_guestGenerationProbability = _s6.guest_generation_probability;
|
||||
gTotalRideValue = _s6.total_ride_value;
|
||||
gMaxBankLoan = _s6.maximum_loan;
|
||||
gGuestInitialCash = _s6.guest_initial_cash;
|
||||
gGuestInitialHunger = _s6.guest_initial_hunger;
|
||||
gGuestInitialThirst = _s6.guest_initial_thirst;
|
||||
gScenarioObjectiveType = _s6.objective_type;
|
||||
gScenarioObjectiveYear = _s6.objective_year;
|
||||
// pad_013580FA
|
||||
gScenarioObjectiveCurrency = _s6.objective_currency;
|
||||
gScenarioObjectiveNumGuests = _s6.objective_guests;
|
||||
memcpy(gMarketingCampaignDaysLeft, _s6.campaign_weeks_left, sizeof(_s6.campaign_weeks_left));
|
||||
memcpy(gMarketingCampaignRideIndex, _s6.campaign_ride_index, sizeof(_s6.campaign_ride_index));
|
||||
|
||||
memcpy(gCashHistory, _s6.balance_history, sizeof(_s6.balance_history));
|
||||
|
||||
RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_EXPENDITURE, money32) = _s6.current_expenditure;
|
||||
RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_PROFIT, money32) = _s6.current_profit;
|
||||
RCT2_GLOBAL(0x01358334, uint32) = _s6.dword_01358334;
|
||||
RCT2_GLOBAL(0x01358338, uint16) = _s6.word_01358338;
|
||||
// pad_0135833A
|
||||
|
||||
memcpy(gWeeklyProfitHistory, _s6.weekly_profit_history, sizeof(_s6.weekly_profit_history));
|
||||
|
||||
gParkValue = _s6.park_value;
|
||||
|
||||
memcpy(gParkValueHistory, _s6.park_value_history, sizeof(_s6.park_value_history));
|
||||
|
||||
gScenarioCompletedCompanyValue = _s6.completed_company_value;
|
||||
RCT2_GLOBAL(RCT2_ADDRESS_TOTAL_ADMISSIONS, money32) = _s6.total_admissions;
|
||||
RCT2_GLOBAL(RCT2_ADDRESS_INCOME_FROM_ADMISSIONS, money32) = _s6.income_from_admissions;
|
||||
gCompanyValue = _s6.company_value;
|
||||
memcpy(RCT2_ADDRESS(0x01358750, uint8), _s6.byte_01358750, sizeof(_s6.byte_01358750));
|
||||
memcpy(gCurrentAwards, _s6.awards, sizeof(_s6.awards));
|
||||
gLandPrice = _s6.land_price;
|
||||
gConstructionRightsPrice = _s6.construction_rights_price;
|
||||
RCT2_GLOBAL(0x01358774, uint16) = _s6.word_01358774;
|
||||
// pad_01358776
|
||||
memcpy(RCT2_ADDRESS(0x01358778, uint32), _s6.dword_01358778, sizeof(_s6.dword_01358778));
|
||||
_gameVersion = _s6.game_version_number;
|
||||
RCT2_GLOBAL(0x013587C0, uint32) = _s6.dword_013587C0;
|
||||
RCT2_GLOBAL(RCT2_ADDRESS_LOAN_HASH, uint32) = _s6.loan_hash;
|
||||
RCT2_GLOBAL(RCT2_ADDRESS_RIDE_COUNT, uint16) = _s6.ride_count;
|
||||
// pad_013587CA
|
||||
RCT2_GLOBAL(0x013587D0, uint32) = _s6.dword_013587D0;
|
||||
// pad_013587D4
|
||||
memcpy(gScenarioCompletedBy, _s6.scenario_completed_name, sizeof(_s6.scenario_completed_name));
|
||||
gCashEncrypted = _s6.cash;
|
||||
// pad_013587FC
|
||||
RCT2_GLOBAL(0x0135882E, uint16) = _s6.word_0135882E;
|
||||
gMapSizeUnits = _s6.map_size_units;
|
||||
gMapSizeMinus2 = _s6.map_size_minus_2;
|
||||
gMapSize = _s6.map_size;
|
||||
gMapSizeMaxXY = _s6.map_max_xy;
|
||||
RCT2_GLOBAL(RCT2_ADDRESS_SAME_PRICE_THROUGHOUT, uint32) = _s6.same_price_throughout;
|
||||
_suggestedGuestMaximum = _s6.suggested_max_guests;
|
||||
gScenarioParkRatingWarningDays = _s6.park_rating_warning_days;
|
||||
RCT2_GLOBAL(RCT2_ADDRESS_LAST_ENTRANCE_STYLE, uint8) = _s6.last_entrance_style;
|
||||
// rct1_water_colour
|
||||
// pad_01358842
|
||||
memcpy(gResearchItems, _s6.research_items, sizeof(_s6.research_items));
|
||||
RCT2_GLOBAL(0x01359208, uint16) = _s6.word_01359208;
|
||||
memcpy(gScenarioName, _s6.scenario_name, sizeof(_s6.scenario_name));
|
||||
memcpy(gScenarioDetails, _s6.scenario_description, sizeof(_s6.scenario_description));
|
||||
gBankLoanInterestRate = _s6.current_interest_rate;
|
||||
// pad_0135934B
|
||||
RCT2_GLOBAL(RCT2_ADDRESS_SAME_PRICE_THROUGHOUT_EXTENDED, uint32) = _s6.same_price_throughout_extended;
|
||||
memcpy(gParkEntranceX, _s6.park_entrance_x, sizeof(_s6.park_entrance_x));
|
||||
memcpy(gParkEntranceY, _s6.park_entrance_y, sizeof(_s6.park_entrance_y));
|
||||
memcpy(gParkEntranceZ, _s6.park_entrance_z, sizeof(_s6.park_entrance_z));
|
||||
memcpy(gParkEntranceDirection, _s6.park_entrance_direction, sizeof(_s6.park_entrance_direction));
|
||||
memcpy(RCT2_ADDRESS(0x0135936C, char), _s6.scenario_filename, sizeof(_s6.scenario_filename));
|
||||
memcpy(RCT2_ADDRESS(0x0135946C, uint8), _s6.saved_expansion_pack_names, sizeof(_s6.saved_expansion_pack_names));
|
||||
memcpy(gBanners, _s6.banners, sizeof(_s6.banners));
|
||||
memcpy(gUserStrings, _s6.custom_strings, sizeof(_s6.custom_strings));
|
||||
RCT2_GLOBAL(RCT2_ADDRESS_CURRENT_TICKS, uint32) = _s6.game_ticks_1;
|
||||
memcpy(RCT2_ADDRESS(RCT2_ADDRESS_RIDE_LIST, rct_ride*), _s6.rides, sizeof(_s6.rides));
|
||||
RCT2_GLOBAL(RCT2_ADDRESS_SAVED_AGE, uint16) = _s6.saved_age;
|
||||
RCT2_GLOBAL(RCT2_ADDRESS_SAVED_VIEW_X, uint16) = _s6.saved_view_x;
|
||||
RCT2_GLOBAL(RCT2_ADDRESS_SAVED_VIEW_Y, uint16) = _s6.saved_view_y;
|
||||
RCT2_GLOBAL(RCT2_ADDRESS_SAVED_VIEW_ZOOM_AND_ROTATION, uint16) = _s6.saved_view_zoom_and_rotation;
|
||||
memcpy(RCT2_ADDRESS(gAnimatedObjects, rct_map_animation), _s6.map_animations, sizeof(_s6.map_animations));
|
||||
// rct1_map_animations
|
||||
RCT2_GLOBAL(0x0138B580, uint16) = _s6.num_map_animations;
|
||||
// pad_0138B582
|
||||
|
||||
_rideRatingsProximityX = _s6.ride_ratings_proximity_x;
|
||||
_rideRatingsProximityY = _s6.ride_ratings_proximity_y;
|
||||
_rideRatingsProximityZ = _s6.ride_ratings_proximity_z;
|
||||
_rideRatingsProximityStartX = _s6.ride_ratings_proximity_start_x;
|
||||
_rideRatingsProximityStartY = _s6.ride_ratings_proximity_start_y;
|
||||
_rideRatingsProximityStartZ = _s6.ride_ratings_proximity_start_z;
|
||||
_rideRatingsCurrentRide = _s6.ride_ratings_current_ride;
|
||||
_rideRatingsState = _s6.ride_ratings_state;
|
||||
_rideRatingsProximityTrackType = _s6.ride_ratings_proximity_track_type;
|
||||
_rideRatingsProximityBaseHeight = _s6.ride_ratings_proximity_base_height;
|
||||
_rideRatingsProximityTotal = _s6.ride_ratings_proximity_total;
|
||||
memcpy(_proximityScores, _s6.ride_ratings_proximity_scores, sizeof(_s6.ride_ratings_proximity_scores));
|
||||
_rideRatingsNumBrakes = _s6.ride_ratings_num_brakes;
|
||||
_rideRatingsNumReversers = _s6.ride_ratings_num_reversers;
|
||||
RCT2_GLOBAL(0x00138B5CE, uint16) = _s6.word_0138B5CE;
|
||||
memcpy(RCT2_ADDRESS(RCT2_ADDRESS_RIDE_MEASUREMENTS, rct_ride_measurement), _s6.ride_measurements, sizeof(_s6.ride_measurements));
|
||||
RCT2_GLOBAL(0x013B0E6C, uint32) = _s6.next_guest_index;
|
||||
gGrassSceneryTileLoopPosition = _s6.grass_and_scenery_tilepos;
|
||||
memcpy(gStaffPatrolAreas, _s6.patrol_areas, sizeof(_s6.patrol_areas));
|
||||
memcpy(gStaffModes, _s6.staff_modes, sizeof(_s6.staff_modes));
|
||||
// unk_13CA73E
|
||||
// pad_13CA73F
|
||||
RCT2_GLOBAL(0x013CA740, uint8) = _s6.byte_13CA740;
|
||||
gClimate = _s6.climate;
|
||||
// pad_13CA741;
|
||||
memcpy(RCT2_ADDRESS(0x013CA742, uint8), _s6.byte_13CA742, sizeof(_s6.byte_13CA742));
|
||||
// pad_013CA747
|
||||
gClimateUpdateTimer = _s6.climate_update_timer;
|
||||
gClimateCurrentWeather = _s6.current_weather;
|
||||
gClimateNextWeather = _s6.next_weather;
|
||||
gClimateNextTemperature = _s6.temperature;
|
||||
gClimateCurrentWeatherEffect = _s6.current_weather_effect;
|
||||
gClimateNextWeatherEffect = _s6.next_weather_effect;
|
||||
gClimateCurrentWeatherGloom = _s6.current_weather_gloom;
|
||||
gClimateNextWeatherGloom = _s6.next_weather_gloom;
|
||||
gClimateCurrentRainLevel = _s6.current_rain_level;
|
||||
gClimateNextRainLevel = _s6.next_rain_level;
|
||||
memcpy(gNewsItems, _s6.news_items, sizeof(_s6.news_items));
|
||||
// pad_13CE730
|
||||
// rct1_scenario_flags
|
||||
gWidePathTileLoopX = _s6.wide_path_tile_loop_x;
|
||||
gWidePathTileLoopY = _s6.wide_path_tile_loop_y;
|
||||
// pad_13CE778
|
||||
|
||||
// Fix and set dynamic variables
|
||||
if (!object_load_entries(_s6.objects)) {
|
||||
throw ObjectLoadException();
|
||||
}
|
||||
reset_loaded_objects();
|
||||
map_update_tile_pointers();
|
||||
reset_0x69EBE4();
|
||||
game_convert_strings_to_utf8();
|
||||
if (FixIssues)
|
||||
{
|
||||
game_fix_save_vars();
|
||||
}
|
||||
}
|
||||
|
||||
extern "C"
|
||||
{
|
||||
/**
|
||||
*
|
||||
* rct2: 0x00675E1B
|
||||
*/
|
||||
int game_load_sv6(SDL_RWops * rw)
|
||||
{
|
||||
if (!sawyercoding_validate_checksum(rw))
|
||||
{
|
||||
log_error("invalid checksum");
|
||||
|
||||
gErrorType = ERROR_TYPE_FILE_LOAD;
|
||||
gGameCommandErrorTitle = STR_FILE_CONTAINS_INVALID_DATA;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool result = false;
|
||||
auto s6Importer = new S6Importer();
|
||||
try
|
||||
{
|
||||
s6Importer->FixIssues = true;
|
||||
s6Importer->LoadSavedGame(rw);
|
||||
s6Importer->Import();
|
||||
|
||||
openrct2_reset_object_tween_locations();
|
||||
result = true;
|
||||
}
|
||||
catch (ObjectLoadException)
|
||||
{
|
||||
set_load_objects_fail_reason();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
delete s6Importer;
|
||||
|
||||
// #2407: Resetting screen time to not open a save prompt shortly after loading a park.
|
||||
gScreenAge = 0;
|
||||
gLastAutoSaveTick = SDL_GetTicks();
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* rct2: 0x00676053
|
||||
* scenario (ebx)
|
||||
*/
|
||||
int scenario_load(const char * path)
|
||||
{
|
||||
bool result = false;
|
||||
auto s6Importer = new S6Importer();
|
||||
try
|
||||
{
|
||||
s6Importer->FixIssues = true;
|
||||
s6Importer->LoadScenario(path);
|
||||
s6Importer->Import();
|
||||
|
||||
openrct2_reset_object_tween_locations();
|
||||
result = true;
|
||||
}
|
||||
catch (ObjectLoadException)
|
||||
{
|
||||
set_load_objects_fail_reason();
|
||||
}
|
||||
catch (IOException)
|
||||
{
|
||||
gErrorType = ERROR_TYPE_FILE_LOAD;
|
||||
gErrorStringId = STR_GAME_SAVE_FAILED;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
gErrorType = ERROR_TYPE_FILE_LOAD;
|
||||
gErrorStringId = STR_FILE_CONTAINS_INVALID_DATA;
|
||||
}
|
||||
delete s6Importer;
|
||||
|
||||
gScreenAge = 0;
|
||||
gLastAutoSaveTick = SDL_GetTicks();
|
||||
return result;
|
||||
}
|
||||
|
||||
int game_load_network(SDL_RWops* rw)
|
||||
{
|
||||
bool result = false;
|
||||
auto s6Importer = new S6Importer();
|
||||
try
|
||||
{
|
||||
s6Importer->LoadSavedGame(rw);
|
||||
s6Importer->Import();
|
||||
|
||||
openrct2_reset_object_tween_locations();
|
||||
result = true;
|
||||
}
|
||||
catch (ObjectLoadException)
|
||||
{
|
||||
set_load_objects_fail_reason();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
delete s6Importer;
|
||||
|
||||
if (!result)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Read checksum
|
||||
uint32 checksum;
|
||||
SDL_RWread(rw, &checksum, sizeof(uint32), 1);
|
||||
|
||||
// Read other data not in normal save files
|
||||
gGamePaused = SDL_ReadLE32(rw);
|
||||
_guestGenerationProbability = SDL_ReadLE32(rw);
|
||||
_suggestedGuestMaximum = SDL_ReadLE32(rw);
|
||||
gCheatsSandboxMode = SDL_ReadU8(rw) != 0;
|
||||
gCheatsDisableClearanceChecks = SDL_ReadU8(rw) != 0;
|
||||
gCheatsDisableSupportLimits = SDL_ReadU8(rw) != 0;
|
||||
gCheatsDisableTrainLengthLimit = SDL_ReadU8(rw) != 0;
|
||||
gCheatsShowAllOperatingModes = SDL_ReadU8(rw) != 0;
|
||||
gCheatsShowVehiclesFromOtherTrackTypes = SDL_ReadU8(rw) != 0;
|
||||
gCheatsFastLiftHill = SDL_ReadU8(rw) != 0;
|
||||
gCheatsDisableBrakesFailure = SDL_ReadU8(rw) != 0;
|
||||
gCheatsDisableAllBreakdowns = SDL_ReadU8(rw) != 0;
|
||||
gCheatsUnlockAllPrices = SDL_ReadU8(rw) != 0;
|
||||
gCheatsBuildInPauseMode = SDL_ReadU8(rw) != 0;
|
||||
gCheatsIgnoreRideIntensity = SDL_ReadU8(rw) != 0;
|
||||
gCheatsDisableVandalism = SDL_ReadU8(rw) != 0;
|
||||
gCheatsDisableLittering = SDL_ReadU8(rw) != 0;
|
||||
gCheatsNeverendingMarketing = SDL_ReadU8(rw) != 0;
|
||||
gCheatsFreezeClimate = SDL_ReadU8(rw) != 0;
|
||||
|
||||
gLastAutoSaveTick = SDL_GetTicks();
|
||||
return 1;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
#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 "../common.h"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include "../scenario.h"
|
||||
}
|
||||
|
||||
/**
|
||||
* Class to import RollerCoaster Tycoon 2 scenarios (*.SC6) and saved games (*.SV6).
|
||||
*/
|
||||
class S6Importer
|
||||
{
|
||||
public:
|
||||
bool FixIssues;
|
||||
|
||||
S6Importer();
|
||||
|
||||
void LoadSavedGame(const utf8 * path);
|
||||
void LoadSavedGame(SDL_RWops *rw);
|
||||
void LoadScenario(const utf8 * path);
|
||||
void LoadScenario(SDL_RWops *rw);
|
||||
void Import();
|
||||
|
||||
private:
|
||||
const utf8 * _s6Path;
|
||||
rct_s6_data _s6;
|
||||
uint8 _gameVersion;
|
||||
};
|
|
@ -6494,7 +6494,7 @@ void game_command_set_ride_appearance(int *eax, int *ebx, int *ecx, int *edx, in
|
|||
case 6:
|
||||
if (apply) {
|
||||
ride->entrance_style = value;
|
||||
RCT2_GLOBAL(0x01358840, uint8) = value;
|
||||
RCT2_GLOBAL(RCT2_ADDRESS_LAST_ENTRANCE_STYLE, uint8) = value;
|
||||
gfx_invalidate_screen();
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -64,19 +64,7 @@ enum {
|
|||
|
||||
typedef void (*ride_ratings_calculation)(rct_ride *ride);
|
||||
|
||||
#define _rideRatingsProximityX RCT2_GLOBAL(0x0138B584, uint16)
|
||||
#define _rideRatingsProximityY RCT2_GLOBAL(0x0138B586, uint16)
|
||||
#define _rideRatingsProximityZ RCT2_GLOBAL(0x0138B588, uint16)
|
||||
#define _rideRatingsCurrentRide RCT2_GLOBAL(0x0138B590, uint8)
|
||||
#define _rideRatingsState RCT2_GLOBAL(0x0138B591, uint8)
|
||||
#define _rideRatingsProximityTrackType RCT2_GLOBAL(0x0138B592, uint8)
|
||||
#define _rideRatingsProximityBaseHeight RCT2_GLOBAL(0x0138B593, uint8)
|
||||
#define _rideRatingsProximityTotal RCT2_GLOBAL(0x0138B594, uint16)
|
||||
#define _rideRatingsProximityStartX RCT2_GLOBAL(0x0138B58A, uint16)
|
||||
#define _rideRatingsProximityStartY RCT2_GLOBAL(0x0138B58C, uint16)
|
||||
#define _rideRatingsProximityStartZ RCT2_GLOBAL(0x0138B58E, uint16)
|
||||
|
||||
static uint16 *_proximityScores = (uint16*)0x0138B596;
|
||||
uint16 *_proximityScores = (uint16*)0x0138B596;
|
||||
|
||||
static const ride_ratings_calculation ride_ratings_calculate_func_table[91];
|
||||
|
||||
|
@ -605,8 +593,8 @@ static void ride_ratings_score_close_proximity(rct_map_element *inputMapElement)
|
|||
case TRACK_ELEM_BRAKES:
|
||||
RCT2_GLOBAL(0x0138B5CA, uint16)++;
|
||||
break;
|
||||
case 211:
|
||||
case 212:
|
||||
case TRACK_ELEM_LEFT_REVERSER:
|
||||
case TRACK_ELEM_RIGHT_REVERSER:
|
||||
RCT2_GLOBAL(0x0138B5CC, uint16)++;
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -20,6 +20,23 @@
|
|||
#include "../common.h"
|
||||
#include "ride.h"
|
||||
|
||||
#define _rideRatingsProximityX RCT2_GLOBAL(0x0138B584, uint16)
|
||||
#define _rideRatingsProximityY RCT2_GLOBAL(0x0138B586, uint16)
|
||||
#define _rideRatingsProximityZ RCT2_GLOBAL(0x0138B588, uint16)
|
||||
#define _rideRatingsCurrentRide RCT2_GLOBAL(0x0138B590, uint8)
|
||||
#define _rideRatingsState RCT2_GLOBAL(0x0138B591, uint8)
|
||||
#define _rideRatingsProximityTrackType RCT2_GLOBAL(0x0138B592, uint8)
|
||||
#define _rideRatingsProximityBaseHeight RCT2_GLOBAL(0x0138B593, uint8)
|
||||
#define _rideRatingsProximityTotal RCT2_GLOBAL(0x0138B594, uint16)
|
||||
#define _rideRatingsProximityStartX RCT2_GLOBAL(0x0138B58A, uint16)
|
||||
#define _rideRatingsProximityStartY RCT2_GLOBAL(0x0138B58C, uint16)
|
||||
#define _rideRatingsProximityStartZ RCT2_GLOBAL(0x0138B58E, uint16)
|
||||
|
||||
#define _rideRatingsNumBrakes RCT2_GLOBAL(0x0138B5CA, uint16)
|
||||
#define _rideRatingsNumReversers RCT2_GLOBAL(0x0138B5CC, uint16)
|
||||
|
||||
extern uint16 *_proximityScores;
|
||||
|
||||
void ride_ratings_update_all();
|
||||
|
||||
#endif
|
||||
|
|
442
src/scenario.c
442
src/scenario.c
|
@ -55,7 +55,7 @@ const rct_string_id ScenarioCategoryStringIds[SCENARIO_CATEGORY_COUNT] = {
|
|||
};
|
||||
|
||||
static char _scenarioPath[MAX_PATH];
|
||||
static const char *_scenarioFileName = "";
|
||||
const char *_scenarioFileName = "";
|
||||
|
||||
char *gScenarioName = RCT2_ADDRESS(RCT2_ADDRESS_SCENARIO_NAME, char);
|
||||
char *gScenarioDetails = RCT2_ADDRESS(RCT2_ADDRESS_SCENARIO_DETAILS, char);
|
||||
|
@ -95,109 +95,6 @@ bool scenario_load_basic(const char *path, rct_s6_header *header, rct_s6_info *i
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* rct2: 0x00676053
|
||||
* scenario (ebx)
|
||||
*/
|
||||
int scenario_load(const char *path)
|
||||
{
|
||||
log_verbose("loading scenario, %s", path);
|
||||
|
||||
SDL_RWops* rw;
|
||||
int i, j;
|
||||
rct_s6_header *s6Header = (rct_s6_header*)0x009E34E4;
|
||||
rct_s6_info *s6Info = (rct_s6_info*)0x0141F570;
|
||||
|
||||
rw = SDL_RWFromFile(path, "rb");
|
||||
if (rw != NULL) {
|
||||
if (!sawyercoding_validate_checksum(rw) && !gConfigGeneral.allow_loading_with_incorrect_checksum) {
|
||||
SDL_RWclose(rw);
|
||||
gErrorType = ERROR_TYPE_FILE_LOAD;
|
||||
gErrorStringId = STR_FILE_CONTAINS_INVALID_DATA;
|
||||
|
||||
log_error("failed to load scenario, invalid checksum");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Read first chunk
|
||||
sawyercoding_read_chunk(rw, (uint8*)s6Header);
|
||||
if (s6Header->type == S6_TYPE_SCENARIO) {
|
||||
// Read second chunk
|
||||
sawyercoding_read_chunk(rw, (uint8*)s6Info);
|
||||
|
||||
// Read packed objects
|
||||
if (s6Header->num_packed_objects > 0) {
|
||||
j = 0;
|
||||
for (i = 0; i < s6Header->num_packed_objects; i++)
|
||||
j += object_load_packed(rw);
|
||||
if (j > 0)
|
||||
object_list_load();
|
||||
}
|
||||
|
||||
uint8 load_success = object_read_and_load_entries(rw);
|
||||
|
||||
// Read flags (16 bytes). Loads:
|
||||
// RCT2_ADDRESS_CURRENT_MONTH_YEAR
|
||||
// RCT2_ADDRESS_CURRENT_MONTH_TICKS
|
||||
// RCT2_ADDRESS_SCENARIO_TICKS
|
||||
sawyercoding_read_chunk(rw, (uint8*)RCT2_ADDRESS_CURRENT_MONTH_YEAR);
|
||||
|
||||
// Read map elements
|
||||
memset((void*)RCT2_ADDRESS_MAP_ELEMENTS, 0, MAX_MAP_ELEMENTS * sizeof(rct_map_element));
|
||||
sawyercoding_read_chunk(rw, (uint8*)RCT2_ADDRESS_MAP_ELEMENTS);
|
||||
|
||||
// Read game data, including sprites
|
||||
sawyercoding_read_chunk(rw, (uint8*)0x010E63B8);
|
||||
|
||||
// Read number of guests in park and something else
|
||||
sawyercoding_read_chunk(rw, (uint8*)RCT2_ADDRESS_GUESTS_IN_PARK);
|
||||
|
||||
// Read ?
|
||||
sawyercoding_read_chunk(rw, (uint8*)RCT2_ADDRESS_LAST_GUESTS_IN_PARK);
|
||||
|
||||
// Read park rating
|
||||
sawyercoding_read_chunk(rw, (uint8*)RCT2_ADDRESS_CURRENT_PARK_RATING);
|
||||
|
||||
// Read ?
|
||||
sawyercoding_read_chunk(rw, (uint8*)RCT2_ADDRESS_ACTIVE_RESEARCH_TYPES);
|
||||
|
||||
// Read ?
|
||||
sawyercoding_read_chunk(rw, (uint8*)RCT2_ADDRESS_CURRENT_EXPENDITURE);
|
||||
|
||||
// Read ?
|
||||
sawyercoding_read_chunk(rw, (uint8*)RCT2_ADDRESS_CURRENT_PARK_VALUE);
|
||||
|
||||
// Read more game data, including research items and rides
|
||||
sawyercoding_read_chunk(rw, (uint8*)RCT2_ADDRESS_COMPLETED_COMPANY_VALUE);
|
||||
|
||||
SDL_RWclose(rw);
|
||||
if (!load_success){
|
||||
log_error("failed to load all entries.");
|
||||
set_load_objects_fail_reason();
|
||||
return 0;
|
||||
}
|
||||
|
||||
reset_loaded_objects();
|
||||
map_update_tile_pointers();
|
||||
reset_0x69EBE4();
|
||||
openrct2_reset_object_tween_locations();
|
||||
game_convert_strings_to_utf8();
|
||||
game_fix_save_vars(); // OpenRCT2 fix broken save games
|
||||
|
||||
gLastAutoSaveTick = SDL_GetTicks();
|
||||
return 1;
|
||||
}
|
||||
|
||||
SDL_RWclose(rw);
|
||||
}
|
||||
|
||||
log_error("failed to find scenario file.");
|
||||
gErrorType = ERROR_TYPE_FILE_LOAD;
|
||||
gErrorStringId = STR_FILE_CONTAINS_INVALID_DATA;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int scenario_load_and_play_from_path(const char *path)
|
||||
{
|
||||
window_close_construction_windows();
|
||||
|
@ -353,7 +250,7 @@ void scenario_begin()
|
|||
duck_remove_all();
|
||||
park_calculate_size();
|
||||
staff_reset_stats();
|
||||
RCT2_GLOBAL(0x01358840, uint8) = 0;
|
||||
RCT2_GLOBAL(RCT2_ADDRESS_LAST_ENTRANCE_STYLE, uint8) = 0;
|
||||
memset((void*)0x001358102, 0, 20);
|
||||
RCT2_GLOBAL(0x00135882E, uint16) = 0;
|
||||
|
||||
|
@ -870,31 +767,10 @@ int scenario_write_available_objects(FILE *file)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static void sub_677552()
|
||||
{
|
||||
RCT2_GLOBAL(RCT2_ADDRESS_GAME_VERSION_NUMBER, uint32) = 201028;
|
||||
RCT2_GLOBAL(0x001358778, uint32) = RCT2_GLOBAL(0x009E2D28, uint32);
|
||||
}
|
||||
|
||||
static void sub_674BCF()
|
||||
{
|
||||
char *savedExpansionPackNames = (char*)0x0135946C;
|
||||
|
||||
for (int i = 0; i < 16; i++) {
|
||||
char *dst = &savedExpansionPackNames[i * 128];
|
||||
if (RCT2_GLOBAL(RCT2_ADDRESS_EXPANSION_FLAGS, uint16) & (1 << i)) {
|
||||
char *src = &(RCT2_ADDRESS(RCT2_ADDRESS_EXPANSION_NAMES, char)[i * 128]);
|
||||
safe_strcpy(dst, src, 128);
|
||||
} else {
|
||||
*dst = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Modifys the given S6 data so that ghost elements, rides with no track elements or unused banners / user strings are saved.
|
||||
* Modifies the given S6 data so that ghost elements, rides with no track elements or unused banners / user strings are saved.
|
||||
*/
|
||||
static void scenario_fix_ghosts(rct_s6_data *s6)
|
||||
void scenario_fix_ghosts(rct_s6_data *s6)
|
||||
{
|
||||
// Remove all ghost elements
|
||||
size_t mapElementTotalSize = MAX_MAP_ELEMENTS * sizeof(rct_map_element);
|
||||
|
@ -925,7 +801,7 @@ static void scenario_fix_ghosts(rct_s6_data *s6)
|
|||
}
|
||||
}
|
||||
|
||||
static void scenario_remove_trackless_rides(rct_s6_data *s6)
|
||||
void scenario_remove_trackless_rides(rct_s6_data *s6)
|
||||
{
|
||||
bool rideHasTrack[MAX_RIDES];
|
||||
ride_all_has_any_track_elements(rideHasTrack);
|
||||
|
@ -943,314 +819,6 @@ static void scenario_remove_trackless_rides(rct_s6_data *s6)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* rct2: 0x006754F5
|
||||
* @param flags bit 0: pack objects, 1: save as scenario
|
||||
*/
|
||||
int scenario_save(SDL_RWops* rw, int flags)
|
||||
{
|
||||
rct_window *w;
|
||||
rct_viewport *viewport;
|
||||
int viewX, viewY, viewZoom, viewRotation;
|
||||
|
||||
if (flags & 2)
|
||||
log_verbose("saving scenario");
|
||||
else
|
||||
log_verbose("saving game");
|
||||
|
||||
|
||||
if (!(flags & 0x80000000))
|
||||
window_close_construction_windows();
|
||||
|
||||
map_reorganise_elements();
|
||||
reset_0x69EBE4();
|
||||
sprite_clear_all_unused();
|
||||
sub_677552();
|
||||
sub_674BCF();
|
||||
|
||||
// Set saved view
|
||||
w = window_get_main();
|
||||
if (w != NULL) {
|
||||
viewport = w->viewport;
|
||||
|
||||
viewX = viewport->view_width / 2 + viewport->view_x;
|
||||
viewY = viewport->view_height / 2 + viewport->view_y;
|
||||
viewZoom = viewport->zoom;
|
||||
viewRotation = get_current_rotation();
|
||||
} else {
|
||||
viewX = gSavedViewX;
|
||||
viewY = gSavedViewY;
|
||||
viewZoom = gSavedViewZoom;
|
||||
viewRotation = gSavedViewRotation;
|
||||
}
|
||||
|
||||
gSavedViewX = viewX;
|
||||
gSavedViewY = viewY;
|
||||
gSavedViewZoom = viewZoom;
|
||||
gSavedViewRotation = viewRotation;
|
||||
|
||||
// Prepare S6
|
||||
rct_s6_data *s6 = malloc(sizeof(rct_s6_data));
|
||||
s6->header.type = flags & 2 ? S6_TYPE_SCENARIO : S6_TYPE_SAVEDGAME;
|
||||
s6->header.num_packed_objects = flags & 1 ? scenario_get_num_packed_objects_to_write() : 0;
|
||||
s6->header.version = S6_RCT2_VERSION;
|
||||
s6->header.magic_number = S6_MAGIC_NUMBER;
|
||||
|
||||
memcpy(&s6->info, (rct_s6_info*)0x0141F570, sizeof(rct_s6_info));
|
||||
|
||||
for (int i = 0; i < OBJECT_ENTRY_COUNT; i++) {
|
||||
rct_object_entry_extended *entry = &(RCT2_ADDRESS(0x00F3F03C, rct_object_entry_extended)[i]);
|
||||
|
||||
if (gObjectList[i] == (void *)0xFFFFFFFF) {
|
||||
memset(&s6->objects[i], 0xFF, sizeof(rct_object_entry));
|
||||
} else {
|
||||
s6->objects[i] = *((rct_object_entry*)entry);
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(&s6->elapsed_months, (void*)0x00F663A8, 16);
|
||||
memcpy(s6->map_elements, (void*)0x00F663B8, 0x180000);
|
||||
memcpy(&s6->dword_010E63B8, (void*)0x010E63B8, 0x2E8570);
|
||||
|
||||
safe_strcpy(s6->scenario_filename, _scenarioFileName, sizeof(s6->scenario_filename));
|
||||
|
||||
scenario_fix_ghosts(s6);
|
||||
scenario_remove_trackless_rides(s6);
|
||||
game_convert_strings_to_rct2(s6);
|
||||
scenario_save_s6(rw, s6);
|
||||
|
||||
free(s6);
|
||||
|
||||
if (flags & 1)
|
||||
reset_loaded_objects();
|
||||
|
||||
gfx_invalidate_screen();
|
||||
if (!(flags & 0x80000000))
|
||||
gScreenAge = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Save game state without modifying any of the state for multiplayer
|
||||
int scenario_save_network(SDL_RWops* rw)
|
||||
{
|
||||
rct_window *w;
|
||||
rct_viewport *viewport;
|
||||
int viewX, viewY, viewZoom, viewRotation;
|
||||
|
||||
/*map_reorganise_elements();
|
||||
reset_0x69EBE4();
|
||||
sprite_clear_all_unused();
|
||||
sub_677552();
|
||||
sub_674BCF();*/
|
||||
|
||||
// Set saved view
|
||||
w = window_get_main();
|
||||
if (w != NULL) {
|
||||
viewport = w->viewport;
|
||||
|
||||
viewX = viewport->view_width / 2 + viewport->view_x;
|
||||
viewY = viewport->view_height / 2 + viewport->view_y;
|
||||
viewZoom = viewport->zoom;
|
||||
viewRotation = get_current_rotation();
|
||||
} else {
|
||||
viewX = 0;
|
||||
viewY = 0;
|
||||
viewZoom = 0;
|
||||
viewRotation = 0;
|
||||
}
|
||||
|
||||
gSavedViewX = viewX;
|
||||
gSavedViewY = viewY;
|
||||
gSavedViewZoom = viewZoom;
|
||||
gSavedViewRotation = viewRotation;
|
||||
|
||||
// Prepare S6
|
||||
rct_s6_data *s6 = malloc(sizeof(rct_s6_data));
|
||||
s6->header.type = S6_TYPE_SAVEDGAME;
|
||||
s6->header.num_packed_objects = scenario_get_num_packed_objects_to_write();
|
||||
s6->header.version = S6_RCT2_VERSION;
|
||||
s6->header.magic_number = S6_MAGIC_NUMBER;
|
||||
|
||||
memcpy(&s6->info, (rct_s6_info*)0x0141F570, sizeof(rct_s6_info));
|
||||
|
||||
for (int i = 0; i < 721; i++) {
|
||||
rct_object_entry_extended *entry = &(RCT2_ADDRESS(0x00F3F03C, rct_object_entry_extended)[i]);
|
||||
|
||||
if (gObjectList[i] == (void *)0xFFFFFFFF) {
|
||||
memset(&s6->objects[i], 0xFF, sizeof(rct_object_entry));
|
||||
} else {
|
||||
s6->objects[i] = *((rct_object_entry*)entry);
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(&s6->elapsed_months, (void*)0x00F663A8, 16);
|
||||
memcpy(s6->map_elements, (void*)0x00F663B8, 0x180000);
|
||||
memcpy(&s6->dword_010E63B8, (void*)0x010E63B8, 0x2E8570);
|
||||
|
||||
safe_strcpy(s6->scenario_filename, _scenarioFileName, sizeof(s6->scenario_filename));
|
||||
|
||||
scenario_fix_ghosts(s6);
|
||||
game_convert_strings_to_rct2(s6);
|
||||
scenario_save_s6(rw, s6);
|
||||
|
||||
free(s6);
|
||||
|
||||
reset_loaded_objects();
|
||||
|
||||
// Write other data not in normal save files
|
||||
SDL_WriteLE32(rw, gGamePaused);
|
||||
SDL_WriteLE32(rw, _guestGenerationProbability);
|
||||
SDL_WriteLE32(rw, _suggestedGuestMaximum);
|
||||
SDL_WriteU8(rw, gCheatsSandboxMode);
|
||||
SDL_WriteU8(rw, gCheatsDisableClearanceChecks);
|
||||
SDL_WriteU8(rw, gCheatsDisableSupportLimits);
|
||||
SDL_WriteU8(rw, gCheatsDisableTrainLengthLimit);
|
||||
SDL_WriteU8(rw, gCheatsShowAllOperatingModes);
|
||||
SDL_WriteU8(rw, gCheatsShowVehiclesFromOtherTrackTypes);
|
||||
SDL_WriteU8(rw, gCheatsFastLiftHill);
|
||||
SDL_WriteU8(rw, gCheatsDisableBrakesFailure);
|
||||
SDL_WriteU8(rw, gCheatsDisableAllBreakdowns);
|
||||
SDL_WriteU8(rw, gCheatsUnlockAllPrices);
|
||||
SDL_WriteU8(rw, gCheatsBuildInPauseMode);
|
||||
SDL_WriteU8(rw, gCheatsIgnoreRideIntensity);
|
||||
SDL_WriteU8(rw, gCheatsDisableVandalism);
|
||||
SDL_WriteU8(rw, gCheatsDisableLittering);
|
||||
SDL_WriteU8(rw, gCheatsNeverendingMarketing);
|
||||
SDL_WriteU8(rw, gCheatsFreezeClimate);
|
||||
|
||||
gfx_invalidate_screen();
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool scenario_save_s6(SDL_RWops* rw, rct_s6_data *s6)
|
||||
{
|
||||
uint8 *buffer;
|
||||
sawyercoding_chunk_header chunkHeader;
|
||||
int encodedLength;
|
||||
long fileSize;
|
||||
uint32 checksum;
|
||||
|
||||
buffer = malloc(0x600000);
|
||||
if (buffer == NULL) {
|
||||
log_error("Unable to allocate enough space for a write buffer.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 0: Write header chunk
|
||||
chunkHeader.encoding = CHUNK_ENCODING_ROTATE;
|
||||
chunkHeader.length = sizeof(rct_s6_header);
|
||||
encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)&s6->header, chunkHeader);
|
||||
SDL_RWwrite(rw, buffer, encodedLength, 1);
|
||||
|
||||
// 1: Write scenario info chunk
|
||||
if (s6->header.type == S6_TYPE_SCENARIO) {
|
||||
chunkHeader.encoding = CHUNK_ENCODING_ROTATE;
|
||||
chunkHeader.length = sizeof(rct_s6_info);
|
||||
encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)&s6->info, chunkHeader);
|
||||
SDL_RWwrite(rw, buffer, encodedLength, 1);
|
||||
}
|
||||
|
||||
// 2: Write packed objects
|
||||
if (s6->header.num_packed_objects > 0) {
|
||||
if (!scenario_write_packed_objects(rw)) {
|
||||
free(buffer);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 3: Write available objects chunk
|
||||
chunkHeader.encoding = CHUNK_ENCODING_ROTATE;
|
||||
chunkHeader.length = 721 * sizeof(rct_object_entry);
|
||||
encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)s6->objects, chunkHeader);
|
||||
SDL_RWwrite(rw, buffer, encodedLength, 1);
|
||||
|
||||
// 4: Misc fields (data, rand...) chunk
|
||||
chunkHeader.encoding = CHUNK_ENCODING_RLECOMPRESSED;
|
||||
chunkHeader.length = 16;
|
||||
encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)&s6->elapsed_months, chunkHeader);
|
||||
SDL_RWwrite(rw, buffer, encodedLength, 1);
|
||||
|
||||
// 5: Map elements + sprites and other fields chunk
|
||||
chunkHeader.encoding = CHUNK_ENCODING_RLECOMPRESSED;
|
||||
chunkHeader.length = 0x180000;
|
||||
encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)s6->map_elements, chunkHeader);
|
||||
SDL_RWwrite(rw, buffer, encodedLength, 1);
|
||||
|
||||
if (s6->header.type == S6_TYPE_SCENARIO) {
|
||||
// 6:
|
||||
chunkHeader.encoding = CHUNK_ENCODING_RLECOMPRESSED;
|
||||
chunkHeader.length = 0x27104C;
|
||||
encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)&s6->dword_010E63B8, chunkHeader);
|
||||
SDL_RWwrite(rw, buffer, encodedLength, 1);
|
||||
|
||||
// 7:
|
||||
chunkHeader.encoding = CHUNK_ENCODING_RLECOMPRESSED;
|
||||
chunkHeader.length = 4;
|
||||
encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)&s6->guests_in_park, chunkHeader);
|
||||
SDL_RWwrite(rw, buffer, encodedLength, 1);
|
||||
|
||||
// 8:
|
||||
chunkHeader.encoding = CHUNK_ENCODING_RLECOMPRESSED;
|
||||
chunkHeader.length = 8;
|
||||
encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)&s6->last_guests_in_park, chunkHeader);
|
||||
SDL_RWwrite(rw, buffer, encodedLength, 1);
|
||||
|
||||
// 9:
|
||||
chunkHeader.encoding = CHUNK_ENCODING_RLECOMPRESSED;
|
||||
chunkHeader.length = 2;
|
||||
encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)&s6->park_rating, chunkHeader);
|
||||
SDL_RWwrite(rw, buffer, encodedLength, 1);
|
||||
|
||||
// 10:
|
||||
chunkHeader.encoding = CHUNK_ENCODING_RLECOMPRESSED;
|
||||
chunkHeader.length = 1082;
|
||||
encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)&s6->active_research_types, chunkHeader);
|
||||
SDL_RWwrite(rw, buffer, encodedLength, 1);
|
||||
|
||||
// 11:
|
||||
chunkHeader.encoding = CHUNK_ENCODING_RLECOMPRESSED;
|
||||
chunkHeader.length = 16;
|
||||
encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)&s6->current_expenditure, chunkHeader);
|
||||
SDL_RWwrite(rw, buffer, encodedLength, 1);
|
||||
|
||||
// 12:
|
||||
chunkHeader.encoding = CHUNK_ENCODING_RLECOMPRESSED;
|
||||
chunkHeader.length = 4;
|
||||
encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)&s6->park_value, chunkHeader);
|
||||
SDL_RWwrite(rw, buffer, encodedLength, 1);
|
||||
|
||||
// 13:
|
||||
chunkHeader.encoding = CHUNK_ENCODING_RLECOMPRESSED;
|
||||
chunkHeader.length = 0x761E8;
|
||||
encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)&s6->completed_company_value, chunkHeader);
|
||||
SDL_RWwrite(rw, buffer, encodedLength, 1);
|
||||
} else {
|
||||
// 6: Everything else...
|
||||
chunkHeader.encoding = CHUNK_ENCODING_RLECOMPRESSED;
|
||||
chunkHeader.length = 0x2E8570;
|
||||
encodedLength = sawyercoding_write_chunk_buffer(buffer, (uint8*)&s6->dword_010E63B8, chunkHeader);
|
||||
SDL_RWwrite(rw, buffer, encodedLength, 1);
|
||||
}
|
||||
|
||||
free(buffer);
|
||||
|
||||
// Determine number of bytes written
|
||||
fileSize = (long)SDL_RWtell(rw);
|
||||
SDL_RWseek(rw, 0, RW_SEEK_SET);
|
||||
|
||||
// Read all written bytes back into a single buffer
|
||||
buffer = malloc(fileSize);
|
||||
SDL_RWread(rw, buffer, fileSize, 1);
|
||||
checksum = sawyercoding_calculate_checksum(buffer, fileSize);
|
||||
free(buffer);
|
||||
|
||||
// Append the checksum
|
||||
SDL_RWseek(rw, fileSize, RW_SEEK_SET);
|
||||
SDL_RWwrite(rw, &checksum, sizeof(uint32), 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void scenario_objective_check_guests_by()
|
||||
{
|
||||
uint8 objectiveYear = gScenarioObjectiveYear;
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "platform/platform.h"
|
||||
#include "world/banner.h"
|
||||
#include "world/map.h"
|
||||
#include "world/map_animation.h"
|
||||
#include "world/sprite.h"
|
||||
|
||||
/**
|
||||
|
@ -126,7 +127,7 @@ typedef struct {
|
|||
// SC6[4]
|
||||
uint16 elapsed_months;
|
||||
uint16 current_day;
|
||||
uint32 dword_F663AC;
|
||||
uint32 scenario_ticks;
|
||||
uint32 scenario_srand_0;
|
||||
uint32 scenario_srand_1;
|
||||
|
||||
|
@ -155,10 +156,10 @@ typedef struct {
|
|||
money32 current_loan;
|
||||
uint32 park_flags;
|
||||
money16 park_entrance_fee;
|
||||
uint16 word_013573EA;
|
||||
uint16 word_013573EC;
|
||||
uint16 rct1_park_entrance_x;
|
||||
uint16 rct1_park_entrance_y;
|
||||
uint8 pad_013573EE[2];
|
||||
uint8 byte_013573F0;
|
||||
uint8 rct1_park_entrance_z;
|
||||
uint8 pad_013573F1;
|
||||
rct2_peep_spawn peep_spawns[2];
|
||||
uint8 guest_count_change_modifier;
|
||||
|
@ -176,7 +177,7 @@ typedef struct {
|
|||
// Ignored in scenario
|
||||
money32 expenditure_table[14];
|
||||
uint32 dword_01357880[5];
|
||||
uint32 dword_01357894;
|
||||
uint32 monthly_ride_income;
|
||||
uint32 dword_01357898;
|
||||
uint32 dword_0135789C;
|
||||
uint32 dword_013578A0;
|
||||
|
@ -202,8 +203,8 @@ typedef struct {
|
|||
// SC6[10]
|
||||
uint8 active_research_types;
|
||||
uint8 research_progress_stage;
|
||||
uint32 dword_01357CF4;
|
||||
uint8 byte_01357CF8[1000];
|
||||
uint32 last_researched_item_subject;
|
||||
uint8 pad_01357CF8[1000];
|
||||
uint32 next_research_item;
|
||||
uint16 research_progress;
|
||||
uint8 next_research_category;
|
||||
|
@ -274,7 +275,7 @@ typedef struct {
|
|||
uint32 same_price_throughout;
|
||||
uint16 suggested_max_guests;
|
||||
uint16 park_rating_warning_days;
|
||||
uint8 word_01358840;
|
||||
uint8 last_entrance_style;
|
||||
uint8 rct1_water_colour;
|
||||
uint8 pad_01358842[2];
|
||||
rct_research_item research_items[500];
|
||||
|
@ -294,12 +295,12 @@ typedef struct {
|
|||
char custom_strings[0x8000];
|
||||
uint32 game_ticks_1;
|
||||
rct_ride rides[255];
|
||||
uint16 word_01388698;
|
||||
uint16 saved_age;
|
||||
uint16 saved_view_x;
|
||||
uint16 saved_view_y;
|
||||
uint16 saved_view_zoom_and_rotation;
|
||||
uint8 map_animations[6000];
|
||||
uint8 byte_01389E10[6000];
|
||||
rct_map_animation map_animations[1000];
|
||||
rct_map_animation rct1_map_animations[1000];
|
||||
uint16 num_map_animations;
|
||||
uint8 pad_0138B582[2];
|
||||
uint16 ride_ratings_proximity_x;
|
||||
|
@ -313,46 +314,20 @@ typedef struct {
|
|||
uint8 ride_ratings_proximity_track_type;
|
||||
uint8 ride_ratings_proximity_base_height;
|
||||
uint16 ride_ratings_proximity_total;
|
||||
uint16 word_0138B596;
|
||||
uint16 word_0138B598;
|
||||
uint16 word_0138B59A;
|
||||
uint16 word_0138B59C;
|
||||
uint16 word_0138B59E;
|
||||
uint16 word_0138B5A0;
|
||||
uint16 word_0138B5A2;
|
||||
uint16 word_0138B5A4;
|
||||
uint16 word_0138B5A6;
|
||||
uint16 word_0138B5A8;
|
||||
uint16 word_0138B5AA;
|
||||
uint16 word_0138B5AC;
|
||||
uint16 word_0138B5AE;
|
||||
uint16 word_0138B5B0;
|
||||
uint16 word_0138B5B2;
|
||||
uint16 word_0138B5B4;
|
||||
uint16 word_0138B5B6;
|
||||
uint16 word_0138B5B8;
|
||||
uint16 word_0138B5BA;
|
||||
uint16 word_0138B5BC;
|
||||
uint16 word_0138B5BE;
|
||||
uint16 word_0138B5C0;
|
||||
uint16 word_0138B5C2;
|
||||
uint16 word_0138B5C4;
|
||||
uint16 word_0138B5C6;
|
||||
uint16 word_0138B5C8;
|
||||
uint16 word_0138B5CA;
|
||||
uint16 word_0138B5CC;
|
||||
uint16 word_0138B5CE[31];
|
||||
uint8 ride_measurements[0x25860];
|
||||
uint16 ride_ratings_proximity_scores[26];
|
||||
uint16 ride_ratings_num_brakes;
|
||||
uint16 ride_ratings_num_reversers;
|
||||
uint16 word_0138B5CE;
|
||||
uint8 pad_0138B5D0[60];
|
||||
rct_ride_measurement ride_measurements[8];
|
||||
uint32 next_guest_index;
|
||||
uint16 grass_and_scenery_tilepos;
|
||||
uint32 patrol_areas[0x6600]; // 512 bytes per staff peep
|
||||
uint8 byte_13CA672[116];
|
||||
uint8 byte_13CA6E6[84];
|
||||
uint8 byte_13CA73A[4];
|
||||
uint8 staff_modes[204];
|
||||
uint8 unk_13CA73E;
|
||||
uint8 pad_13CA73F;
|
||||
uint8 byte_13CA740;
|
||||
uint8 byte_13CA741;
|
||||
uint8 pad_13CA741;
|
||||
uint8 byte_13CA742[4];
|
||||
uint8 climate;
|
||||
uint8 pad_013CA747;
|
||||
|
@ -368,8 +343,8 @@ typedef struct {
|
|||
uint8 current_rain_level;
|
||||
uint8 next_rain_level;
|
||||
rct_news_item news_items[61];
|
||||
uint8 byte_13CE730[64];
|
||||
uint32 dword_13CE770;
|
||||
uint8 pad_13CE730[64];
|
||||
uint32 rct1_scenario_flags;
|
||||
uint16 wide_path_tile_loop_x;
|
||||
uint16 wide_path_tile_loop_y;
|
||||
uint8 pad_13CE778[434];
|
||||
|
@ -480,6 +455,8 @@ extern char gScenarioSavePath[MAX_PATH];
|
|||
extern int gFirstTimeSave;
|
||||
extern uint32 gLastAutoSaveTick;
|
||||
|
||||
extern const char *_scenarioFileName;
|
||||
|
||||
bool scenario_scores_save();
|
||||
void scenario_load_list();
|
||||
void scenario_list_dispose();
|
||||
|
@ -497,7 +474,10 @@ unsigned int scenario_rand_max(unsigned int max);
|
|||
int scenario_prepare_for_save();
|
||||
int scenario_save(SDL_RWops* rw, int flags);
|
||||
int scenario_save_network(SDL_RWops* rw);
|
||||
bool scenario_save_s6(SDL_RWops* rw, rct_s6_data *s6);
|
||||
int scenario_get_num_packed_objects_to_write();
|
||||
int scenario_write_packed_objects(SDL_RWops* rw);
|
||||
void scenario_remove_trackless_rides(rct_s6_data *s6);
|
||||
void scenario_fix_ghosts(rct_s6_data *s6);
|
||||
void scenario_set_filename(const char *value);
|
||||
void scenario_failure();
|
||||
void scenario_success();
|
||||
|
|
Loading…
Reference in New Issue