diff --git a/projects/openrct2.vcxproj b/projects/openrct2.vcxproj index 17fd85d97e..41b6e1cb2f 100644 --- a/projects/openrct2.vcxproj +++ b/projects/openrct2.vcxproj @@ -136,6 +136,7 @@ + @@ -194,6 +195,7 @@ + diff --git a/projects/openrct2.vcxproj.filters b/projects/openrct2.vcxproj.filters index 79ac5f6879..8e61b709f5 100644 --- a/projects/openrct2.vcxproj.filters +++ b/projects/openrct2.vcxproj.filters @@ -382,15 +382,11 @@ - Source\Drawing - - Libraries\lodepng - Libraries\libspeex @@ -422,6 +418,10 @@ Source\World + + + Source\World + @@ -616,5 +616,8 @@ Libraries\argparse + + Source\World + \ No newline at end of file diff --git a/src/editor.c b/src/editor.c index 30fc1f4785..00212ac0c0 100644 --- a/src/editor.c +++ b/src/editor.c @@ -32,11 +32,19 @@ #include "object.h" #include "peep/staff.h" #include "ride/ride.h" +#include "util/sawyercoding.h" +#include "world/banner.h" #include "world/map.h" #include "world/park.h" #include "world/sprite.h" static void set_all_land_owned(); +static int editor_load_landscape_from_sv4(const char *path); +static int editor_load_landscape_from_sc4(const char *path); +static int editor_read_sc4(char *src, int length); +static int editor_read_sv4(char *src, int length); +static int editor_read_s4(char *src); +static int editor_read_s6(const char *path); /*Syntax error blah blah blat *&2)*/ @@ -166,16 +174,6 @@ void trackmanager_load() rct2_endupdate(); } -/** - * - * rct2: 0x006758C0 - */ -void editor_load_landscape(const char *path) -{ - strcpy((char *)0x0141EF68, path); - RCT2_CALLPROC_EBPSAFE(0x006758C0); -} - /** * * rct2: 0x0068ABEC @@ -201,3 +199,202 @@ void sub_6BD3A4() { //RCT2_CALLPROC_EBPSAFE(0x006C0C3F); sub_6C0C3F(); } + +static void read(void *dst, void **src, int length) +{ + memcpy(dst, *src, length); + *((char**)src) += length; +} + +/** + * + * rct2: 0x006758C0 + */ +void editor_load_landscape(const char *path) +{ + window_close_construction_windows(); + + char *extension = strrchr(path, '.'); + if (extension != NULL) { + if (_stricmp(extension, ".sv4") == 0) { + editor_load_landscape_from_sv4(path); + return; + } else if (_stricmp(extension, ".sc4") == 0) { + editor_load_landscape_from_sc4(path); + return; + } + } + + // Load SC6 / SV6 + editor_read_s6(path); +} + +/** + * + * rct2: 0x006A2B02 + */ +static int editor_load_landscape_from_sv4(const char *path) +{ + FILE *fp; + long fpLength; + char *fpBuffer; + + // Open file + fp = fopen(path, "rb"); + if (fp == NULL) { + RCT2_GLOBAL(0x009AC31B, uint8) = 255; + RCT2_GLOBAL(0x009AC31C, uint16) = 3011; + return 0; + } + + // Get length + fseek(fp, 0, SEEK_END); + fpLength = ftell(fp); + rewind(fp); + + // Read whole file into a buffer + fpBuffer = malloc(fpLength); + fread(fpBuffer, fpLength, 1, fp); + fclose(fp); + + editor_read_sv4(fpBuffer, fpLength); + free(fpBuffer); + + RCT2_CALLPROC_EBPSAFE(0x006A2B62); + return 1; +} + +static int editor_load_landscape_from_sc4(const char *path) +{ + FILE *fp; + long fpLength; + char *fpBuffer; + + // Open file + fp = fopen(path, "rb"); + if (fp == NULL) { + RCT2_GLOBAL(0x009AC31B, uint8) = 255; + RCT2_GLOBAL(0x009AC31C, uint16) = 3011; + return 0; + } + + // Get length + fseek(fp, 0, SEEK_END); + fpLength = ftell(fp); + rewind(fp); + + // Read whole file into a buffer + fpBuffer = malloc(fpLength); + fread(fpBuffer, fpLength, 1, fp); + fclose(fp); + + editor_read_sc4(fpBuffer, fpLength); + free(fpBuffer); + + RCT2_CALLPROC_EBPSAFE(0x006A2B62); + return 1; +} + +static int editor_read_sc4(char *src, int length) +{ + int decodedLength; + char *decodedBuffer; + + decodedBuffer = malloc(2065676); + decodedLength = sawyercoding_decode_sc4(src, decodedBuffer, length); + if (decodedLength != 2065676) { + free(decodedBuffer); + return 0; + } + + editor_read_s4(decodedBuffer); + free(decodedBuffer); + return 1; +} + +static int editor_read_sv4(char *src, int length) +{ + int decodedLength; + char *decodedBuffer; + + decodedBuffer = malloc(2065676); + decodedLength = sawyercoding_decode_sv4(src, decodedBuffer, length); + if (decodedLength != 2065676) { + free(decodedBuffer); + return 0; + } + + editor_read_s4(decodedBuffer); + free(decodedBuffer); + return 1; +} + +/** + * + * rct2: 0x0069EEA0 + */ +static int editor_read_s4(char *src) +{ + int i; + rct_banner *banner; + + read((void*)RCT2_ADDRESS_CURRENT_MONTH_YEAR, &src, 16); + memset((void*)RCT2_ADDRESS_MAP_ELEMENTS, 0, 0x60000 * 4); + read((void*)RCT2_ADDRESS_MAP_ELEMENTS, &src, 0x60000); + read((void*)0x010E63B8, &src, 0x138804); + + for (i = 0; i < MAX_BANNERS; i++) + gBanners[i].var_00 = 255; + + read((void*)0x013573BC, &src, 12424); + + for (i = 0; i < MAX_BANNERS; i++) { + banner = &gBanners[i]; + if (banner->var_00 != 255 && banner->var_02 != 3458) + banner->var_02 = 778; + } + + read((void*)0x0135A8F4, &src, 0x2F51C); + memset((void*)0x013CA672, 0, 204); + read((void*)0x0138B580, &src, 0x258F2); + read((void*)0x013C6A72, &src, 0x3C00); + + char *esi = (char*)0x13C6A72; + char *edi = (char*)0x13B0E72; + int ebx, edx = 116; + do { + ebx = 32; + do { + memcpy(edi, esi, 4); esi += 4; edi += 4; + memset(edi, 0, 4); edi += 4; + } while (--ebx > 0); + memset(edi, 0, 64); edi += 64; + } while (--edx > 0); + edi += 0xA800; + + edx = 4; + do { + ebx = 32; + do { + memcpy(edi, esi, 4); esi += 4; edi += 4; + memset(edi, 0, 4); edi += 4; + } while (--ebx); + memset(edi, 0, 64); edi += 64; + } while (--edx); + + read((void*)0x013CA672, &src, 116); + read((void*)0x013CA73A, &src, 4); + read((void*)0x013CA73E, &src, 0x41EA); + return 1; +} + +/** + * + * rct2: 0x006758FE + */ +static int editor_read_s6(const char *path) +{ + strcpy((char *)0x0141EF68, path); + RCT2_CALLPROC_EBPSAFE(0x006758FE); + return 1; +} \ No newline at end of file diff --git a/src/openrct2.c b/src/openrct2.c index 46e6e2ad19..8b8c7c6ee9 100644 --- a/src/openrct2.c +++ b/src/openrct2.c @@ -28,6 +28,7 @@ #include "openrct2.h" #include "platform/platform.h" #include "platform/osinterface.h" +#include "util/sawyercoding.h" int gOpenRCT2StartupAction = STARTUP_ACTION_TITLE; char gOpenRCT2StartupActionPath[512] = { 0 }; diff --git a/src/util/sawyercoding.c b/src/util/sawyercoding.c index 5443b2c4b9..f6dac8a145 100644 --- a/src/util/sawyercoding.c +++ b/src/util/sawyercoding.c @@ -303,3 +303,46 @@ void encode_chunk_rotate(char *buffer, int length) code = (code + 2) % 8; } } + +int sawyercoding_decode_sv4(char *src, char *dst, int length) +{ + // (0 to length - 4): RLE chunk + // (length - 4 to length): checksum + return decode_chunk_rle(src, dst, length - 4); +} + +int sawyercoding_decode_sc4(char *src, char *dst, int length) +{ + int decodedLength, i; + uint32 *code; + + // Uncompress + decodedLength = decode_chunk_rle(src, dst, length - 4); + + // Decode + for (i = 0x60018; i <= min(decodedLength - 1, 0x1F8353); i++) + dst[i] = dst[i] ^ 0x9C; + + for (i = 0x60018; i <= min(decodedLength - 1, 0x1F8350); i += 4) { + dst[i + 1] = ror8(dst[i + 1], 3); + + code = (uint32*)&dst[i]; + *code = rol32(*code, 9); + } + + return decodedLength; +} + +int sawyercoding_encode_sv4(char *src, char *dst, int length) +{ + int encodedLength, checksum; + + // Encode + encodedLength = encode_chunk_rle(src, dst, length); + + // Append checksum + checksum = sawyercoding_calculate_checksum(dst, encodedLength); + *((uint32*)&dst[encodedLength]) = checksum; + + return encodedLength + 4; +} \ No newline at end of file diff --git a/src/util/sawyercoding.h b/src/util/sawyercoding.h index 7f990c589e..bd2d99a61d 100644 --- a/src/util/sawyercoding.h +++ b/src/util/sawyercoding.h @@ -40,5 +40,8 @@ int sawyercoding_validate_checksum(FILE *file); int sawyercoding_calculate_checksum(uint8* buffer, uint32 length); int sawyercoding_read_chunk(FILE *file, uint8 *buffer); int sawyercoding_write_chunk_buffer(uint8 *dst_file, uint8* buffer, sawyercoding_chunk_header chunkHeader); +int sawyercoding_decode_sv4(char *src, char *dst, int length); +int sawyercoding_decode_sc4(char *src, char *dst, int length); +int sawyercoding_encode_sv4(char *src, char *dst, int length); #endif diff --git a/src/world/banner.c b/src/world/banner.c new file mode 100644 index 0000000000..9a957a83b1 --- /dev/null +++ b/src/world/banner.c @@ -0,0 +1,24 @@ +/***************************************************************************** + * Copyright (c) 2014 Ted John, Matthias Lanzinger + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * This file is part of 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. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + *****************************************************************************/ + +#include "../addresses.h" +#include "banner.h" + +rct_banner *gBanners = (rct_banner*)0x0135A124; \ No newline at end of file diff --git a/src/world/banner.h b/src/world/banner.h new file mode 100644 index 0000000000..6c1af914a3 --- /dev/null +++ b/src/world/banner.h @@ -0,0 +1,37 @@ +/***************************************************************************** + * Copyright (c) 2014 Ted John + * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. + * + * This file is part of 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. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + *****************************************************************************/ + +#ifndef _BANNER_H_ +#define _BANNER_H_ + +#include "../common.h" + +#define MAX_BANNERS 250 + +typedef struct { + uint8 var_00; + uint8 pad_01; + uint16 var_02; + uint8 pad_04[4]; +} rct_banner; + +extern rct_banner *gBanners; + +#endif